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 类一起用于许多正则表达式。例如<name>(.*?)</name>
会很高兴地捕获name
标签中的所有内容,无论是否为utf-8。但是,一旦您开始使用快捷方式,它就会失败。例如\w
等价于[a-zA-Z_]
所以它是字母...对于ASCII,并且不会匹配拉丁字母之外的字母或连字符等...此外,由于它不知道多字节编码,即使@ 987654332@ 可能无法按预期工作:它将捕获 1 到 26 个字节,而不是代码点或字符。以上是关于C ++ 11字符串开头的不区分大小写的比较(unicode)的主要内容,如果未能解决你的问题,请参考以下文章