C ++ 11字符串开头的不区分大小写的比较(unicode)

Posted

技术标签:

【中文标题】C ++ 11字符串开头的不区分大小写的比较(unicode)【英文标题】:C++11 case insensitive comparison of beginning of a string (unicode) 【发布时间】:2012-05-04 07:25:50 【问题描述】:

我必须检查特定字符串是否以另一个字符串开头。字符串使用utf8编码,比较不区分大小写。

我知道这与 Case insensitive string comparison in C++ 的主题非常相似,但我不想使用 boost 库,我更喜欢可移植的解决方案(如果“几乎”不可能,我更喜欢面向 Linux 的解决方案)。

在 C++11 中是否可以使用其正则表达式库?还是只使用简单的字符串比较方法?

【问题讨论】:

你为什么不想使用 boost(它实际上是当今所有开发机器上的标准)。 尝试使用兼容 unicode 的可移植字符串库,例如 ICU。不过,我真的不明白为什么您可以使用一种便携式解决方案而不是另一种。 这看起来很简单,但问题远比您想象的要多。首先,视觉字符有许多不同的可能表示形式:例如,字符é 有自己的代码点,但也可以通过使用字符e 后跟重音代码点来实现。您的解决方案需要意识到这一点。其次,不区分大小写的比较通常采用字符串并将它们大写/小写。这实际上是一个区域敏感的操作:例如,德语字母ßss 的简写,它的大写版本是SS 换句话说,你当然不想滚动你自己的库来处理 Unicode 字符串,因为 C++ 没有内置的功能,你必须选择你的毒药. 好的。出于教育目的学习手动操作是一个很好的理由。但是一旦你进入现实世界,stl/boost 是必不可少的。 【参考方案1】:

我知道的唯一方法是 UTF8/国际化/文化意识是优秀且维护良好的IBM ICU: International Components for Unicode。它是一个用于 *nix 或 Windows 的 C/C++ 库,已经进行了大量研究以提供一个文化感知字符串库,包括既快速又准确的不区分大小写的字符串比较。

恕我直言,除非你正在写论文,否则你永远不应该自己写的两件事是加密和文化敏感的字符串库。

【讨论】:

我不确定只有这两个,但我完全同意这不是一个人可能会做对的事情!【参考方案2】:

对您正在查找的字符串中的内容是否有任何限制 为了?它是用户输入,可以是任何 UTF-8 字符串,问题是 极其复杂。正如其他人所提到的,一个角色可以拥有 几种不同的表示,所以你可能不得不规范化 首先是字符串。然后:什么是平等的?应该'E'比较 等于'é'(在法语的某些圈子中很常见),或者不等于(哪个 将符合 Imprimerie nationale 的“官方”规则)。

除了最琐碎的定义之外,所有的定义都随心所欲 代表着重大的努力。对于这种事情,图书馆ICU 是参考。它包含您需要的一切。但请注意 它适用于 UTF16,而不是 UTF8,因此您必须转换字符串 首先,以及对它们进行规范化。 (ICU 对两者都有支持。)

【讨论】:

很遗憾它选择了 UTF-16。我希望有一个可以直接处理 UTF-8 的库版本:x 我必须过滤出姓名和姓氏列表。它们可以包含任何基于拉丁字母的字符。我认为每个民族字符(如 é)都有自己的大写变体。并且应该只等于它。 @MiniKarol 字符之间的等价性非常依赖于语言环境。在法语中,省略大写重音是很常见的(尽管恕我直言不是很好的做法),所以'E' 将是'e''é''è''ë' 和@987654328 的(不明确的)大写字母@。在瑞士德语中,"Ae"'ä' 的标准大写字母。 (注意大写需要两个码位,小写可能只有一个码位。) @MiniKarol 更不用说德国人'ß',它的大写形式取决于单词(至少根据 Duden 的说法)。您可以通过转换为规范化形式 D 并忽略文本中的各种组合重音来完全忽略重音;这是一个简单(但不太准确)的解决方案,但在大写和小写代码点数不同的情况下仍然不起作用。【参考方案3】:

使用 stl 正则表达式类,您可以执行以下 sn-p 之类的操作。不幸的是它不是 utf8。将str2 更改为std::wstring str2 = L"hello World" 会导致大量转换警告。将 str1 设为 std::wchar 根本不起作用,因为 std::regex 不允许 whar 输入(据我所知)。

#include <regex>
#include <iostream>
#include <string>

int main()

    //The input strings
    std::string str1 = "Hello";
    std::string str2 = "hello World";

    //Define the regular expression using case-insensitivity
    std::regex regx(str1, std::regex_constants::icase);

    //Only search at the beginning 
    std::regex_constants::match_flag_type fl = std::regex_constants::match_continuous;

    //display some output
    std::cout << std::boolalpha << std::regex_search(str2.begin(), str2.end(), regx, fl) << std::endl;

    return 0;

【讨论】:

没错。但在我的回答中,我说 std::regex 不适用于 wchar ,所以我希望它是一个有效的答案,因为它用“否”回答第一个问题 问题是,utf-8 使用普通的std::string,所以在后台使用char 假设我们有一个基于字符的 utf8 实现,这意味着一个 utf8 符号可以表示为 1-4 长度的字符串。 utf8 单词不是看起来像一个“普通”字符串,因此可以由正则表达式类处理吗?好吧,不区分大小写是行不通的,但理论上... 它可以与 regex 类一起用于许多正则表达式。例如&lt;name&gt;(.*?)&lt;/name&gt; 会很高兴地捕获name 标签中的所有内容,无论是否为utf-8。但是,一旦您开始使用快捷方式,它就会失败。例如\w 等价于[a-zA-Z_] 所以它是字母...对于ASCII,并且不会匹配拉丁字母之外的字母或连字符等...此外,由于它不知道多字节编码,即使@ 987654332@ 可能无法按预期工作:它将捕获 1 到 26 个字节,而不是代码点或字符。

以上是关于C ++ 11字符串开头的不区分大小写的比较(unicode)的主要内容,如果未能解决你的问题,请参考以下文章

不改变 POJO 的不区分大小写的 JSON 到 POJO 的映射

c_cpp 不区分大小写的字符串比较

C++ , winapi 比较两个 WCHAR * 字符串

SQL(MySQL):匹配字符串中任何单词的首字母?

字符串与 Java 枚举的不区分大小写匹配

是否有 C# 不区分大小写的等于运算符?