不区分大小写的操作
Posted
技术标签:
【中文标题】不区分大小写的操作【英文标题】:Case insensitive operations 【发布时间】:2016-03-24 14:13:44 【问题描述】:我正在做一个项目,其中区分大小写的操作需要替换为。在对此进行了一些阅读之后,要考虑的数据类型是:
-
ASCII 字符
非 ASCII 字符
Unicode 字符
如果我遗漏了列表中的任何内容,请告诉我。
以上是否需要单独处理,或者是否有 C++ 库可以处理所有这些而不考虑数据类型?
具体来说:
boost 库是否对此提供支持?如果有,是否有关于如何使用 API 的示例或文档?
我了解了 IBM 的 Unicode 国际组件 (ICU)。这是一个为提供支持的库吗?如果有,是否有关于如何使用 API 的示例或文档?
最后,在上述(和其他)方法中,哪种方法更好,为什么?
谢谢!
根据cmets和答案,我写了一个示例程序来更好地理解这一点:
#include <iostream> // std::cout
#include <string> // std::string
#include <locale> // std::locale, std::tolower
using namespace std;
void ascii_to_lower(string& str)
std::locale loc;
std::cout << "Ascii string: " << str;
std::cout << "Lower case: ";
for (std::string::size_type i=0; i<str.length(); ++i)
std::cout << std::tolower(str[i],loc);
return;
void non_ascii_to_lower(void)
std::locale::global(std::locale("en_US.UTF-8"));
std::wcout.imbue(std::locale());
const std::ctype<wchar_t>& f = std::use_facet<std::ctype<wchar_t> >(std::local
std::wstring str = L"Zoë Saldaña played in La maldición del padre Cardona.";
std::wcout << endl << "Non-Ascii string: " << str << endl;
f.tolower(&str[0], &str[0] + str.size());
std::wcout << "Lower case: " << str << endl;
return;
void non_ascii_to_upper(void)
std::locale::global(std::locale("en_US.UTF-8"));
std::wcout.imbue(std::locale());
const std::ctype<wchar_t>& f = std::use_facet<std::ctype<wchar_t> >(std::local
std::wstring str = L"¥£ªÄë";
std::wcout << endl << "Non-Ascii string: " << str << endl;
f.toupper(&str[0], &str[0] + str.size());
std::wcout << "Upper case: " << str << endl;
return;
int main ()
string str="Test String.\n";
ascii_to_lower(str);
non_ascii_to_upper();
non_ascii_to_lower();
return 0;
输出是:
Ascii 字符串:测试字符串。 小写:测试字符串。
非ASCII字符串:▒▒▒▒▒ 大写:▒▒▒▒▒
非 Ascii 字符串:Zo▒ Salda▒a 在 La maldici▒n del padre Cardona 中演奏。 小写:zo▒ salda▒a 在 la maldici▒n del padre cardona 演奏。
非 ascii 字符串,虽然似乎被转换为大小写,但有些文本在输出中不可见。为什么是这样?
总体来说,示例代码看起来还可以吗?
【问题讨论】:
您可以将 ASCII 和非 ASCII 转换为 utf-32,并将它们与 unicode 字符串本身一起视为 std::wstring。您可以使用 std::to_lower 删除大小写因素。 @LibertyPaul 你的意思是std::u32string
?
@LibertyPaul wchart_t 在 Windows 上不是 32 位。
@LibertyPaul 当它最初在 15 年前创建时,wchar_t 能够处理所有定义的代码点,但现在不行了。这个请求的真正问题是许多语言对大小写转换都有上下文要求 - 例如希腊语中的大写 sigma 0x3A3 应该变成 0x03C3 或 0x03C2,这取决于它是否位于单词的末尾。这个用例是什么 - 它是一个必须支持任何字符集/语言的国际应用程序,还是其他什么?
unicode大小写被this thread覆盖
【参考方案1】:
我对这个问题有点惊讶。 boost case conversion
的简单搜索作为第一个条目:Usage - 1.41.0 - Boost,其中有一个关于大小写转换的条目。
搜索stl case conversion
有一个条目tolower - C++ Reference - Cplusplus.com,它还显示了如何使用STL 进行转换。
要进行不区分大小写的搜索,请将两者都转换为小写或大写并进行比较。
来自 boost.org 的代码示例:
string str1("HeLlO WoRld!");
to_upper(str1); // str1=="HELLO WORLD!"
来自 Cplusplus.com 的示例:
// tolower example (C++)
#include <iostream> // std::cout
#include <string> // std::string
#include <locale> // std::locale, std::tolower
int main ()
std::locale loc;
std::string str="Test String.\n";
for (std::string::size_type i=0; i<str.length(); ++i)
std::cout << std::tolower(str[i],loc);
return 0;
对于 ASCII 字符(ASCII 值
关于马特乔丹的评论:
这个请求的真正问题是许多语言对大小写转换都有上下文要求 - 例如希腊语中的大写 sigma 0x3A3 应该变成 0x03C3 或 0x03C2,这取决于它是否位于单词的末尾。
如果 boost 库支持这一点,我会感到非常惊喜。如果没有,您将不得不对其进行测试并报告错误。他们的页面上没有参考说明他们是否进行任何上下文案例转换。一种解决方法可能是测试转换为小写和比较,以及转换为大写和比较。如果其中任何一个为真,则存在匹配,这应该适用于 99.99% 的情况。
Bjarne Stroustrup 的一篇有趣的论文,发现于here,是一本关于语言环境的好书。
【讨论】:
谢谢!我添加了一个示例代码来更好地理解这一点。【参考方案2】:你已经对 boost 有了一个很好的答案。这里有一些补充说明:
字符编码
ASCII 字符编码为 7 位。 ISO 8859-1 和 windows-1252 通过使用第 8 位,用一组有限的国际字符扩展 ASCII。
Unicode 标准进一步扩展了 ASCII,并在 32 位上定义。有几种编码可用:32 位的UTF32 是最简单的(1 个 unicode 字符 = 1 个字符),但UTF16 和UTF8 编码允许使用更小的字符以可变大小的编码存储 Unicode 文本。
更困难的是,不同的操作系统使用不同的约定。在 linux 上,wchart_t
通常是用于 unicode 的 32 位宽字符,wstring
是基于wchar_t
的字符串,char
使用 UTF8 编码。在windows上wchar_t
被定义为16位,因为windows的原生编码是UCS-2(unicode的一个子集),而char
一般理解为win1252。
处理字符大小和编码
所以回到你的问题,有两个方面需要考虑:
存储 - 如果你想要一个适合所有的大小,你可以使用char32_t,它可以像任何 unicode 字符一样保存 ASCII。并为字符串使用basic_string<char32_t>
或u32string
,它们支持您用于处理普通字符串的所有功能。或者您可以使用普通字符串并遵守UTF 8 everywhere。
编码 - 您的应用程序如何解释 char 中包含的值,以及执行转换为小写或大写等操作。这在适用的locale
中定义。
幸运的是,C++ 标准库可以应对所有这些方面:
语言环境有助于使用适当的编码管理@987654331@ 和小写转换和测试(例如isupper()
、isalpha()
、...)
codecvt 允许在各种编码之间进行转换
其他库
ICU 库似乎不提供不区分大小写的比较。它提供对文本处理的支持,例如,遍历文本元素、使用排序规则等。
我建议继续使用标准库或 boost,因为它们享有广泛的支持。
【讨论】:
谢谢!我添加了一个示例代码来更好地理解这一点。 @Maddy 您的区域设置的第一部分对应于 en=english 语言和 US=usa 国家/地区设置,例如货币。英语只知道 a-z 而没有特殊的字符用于上转换。将西班牙语设置为语言以获得 Zoë 的正确转换。 并在您的 linux 系统上查找支持的语言环境:cyberciti.biz/faq/how-to-set-locales-i18n-on-a-linux-unix 我基本上是在寻找一个库或 API,它通过隐藏文本是 ascii 还是非 ascii 以及所涉及的编码类型的细节来提供不区分大小写的操作看起来无缝。我应该能够将手头的字符串(例如,非 ascii)传递给 API,并且它应该对字符串执行建议的操作,而无需用户费心设置语言环境和其他内容。我们有这样的事吗? 用例:假设我的应用程序最初接收到一个字符串为“Zoë Saldaña”,它应该存储它而不需要知道字符串的类型。随后,如果它接收到一个字符串“zoë saLdañA”,那么这与第一个字符串之间的比较应该会导致匹配,只需调用一个 API。因此,寻找一组以适当格式存储字符串的 API,然后检索它并进行不区分大小写的比较。以上是关于不区分大小写的操作的主要内容,如果未能解决你的问题,请参考以下文章