在std::string中处理波兰字符

4

我有一个问题。我正在为Linux编写一款使用波兰语(当然包括波兰字符)的应用程序,编译时收到80个警告,这些只是“警告:多字符字符常量”和“警告:情况标签值超过类型的最大值”。我正在使用std :: string。

我该如何替换std :: string类?

请帮忙。 提前致谢。 问候。

3个回答

4

std::string没有定义特定的编码。因此,您可以在其中存储任何字节序列。但需要注意以下细节:

  1. .c_str()将返回一个以null结尾的缓冲区。如果您的字符集允许null字节,请不要将此字符串传递给不带长度参数的const char*参数的函数,否则您的数据将被截断。
  2. char并不表示一个字符,而是一个字节。在计算机历史上,这是我认为最棘手的术语。请注意,根据UTF-16规范化,wchar_t也不一定保存完整的字符。
  3. .size().length()将返回字节数,而不是字符数。

[编辑]关于case标签的警告与问题(2)有关。您正在使用类型为char的多字节字符的switch语句,该类型不能保存多个字节。[/编辑]

因此,只要遵守这三条规则,您就可以在应用程序中使用std::string。这涉及到STL,包括std::find(),这些都是由此引起的。由于规范化形式的原因,您需要使用一些更聪明的字符串匹配算法来正确支持Unicode。

但是,在任何使用非ASCII字符的语言编写应用程序时(如果您很谨慎,请将其视为[0,128)之外的任何内容),您需要了解不同文本数据源中的编码。

  1. 源文件编码可能未指定,并且可能会受到使用编译器选项更改的影响。任何字符串字面量都将受到此规则的影响。我猜这就是为什么您会收到警告的原因。
  2. 您将从外部来源(文件、用户输入等)获得各种字符编码。当该来源指定编码或您可以从某些外部来源(即询问导入数据的用户)获取编码时,这更容易。许多(较新的)Internet协议强制执行ASCII或UTF-8,除非另有规定。

这两个问题都没有被任何特定的字符串类解决。您只需要将所有外部来源转换为内部编码。我建议始终使用UTF-8,但在Linux上尤其如此,因为它具有本地支持。我强烈建议将您的字符串字面量放在消息文件中,以忘记问题(1)并仅处理问题(2)。

我不建议在Linux上使用std::wstring,因为100%的本机API使用带有const char*函数签名,并且对UTF-8提供了直接支持。如果您使用任何基于wchar_t的字符串类,您将不断需要转换为/从std::wstring,最终可能出错,并使所有事情变慢。
如果您要编写适用于Windows的应用程序,则建议恰好相反,因为所有本机API都使用const wchar_t*签名。此类功能的ANSI版本执行与const wchar_t*之间的内部转换。
一些“可移植”的库/语言基于平台使用不同的表示。它们在Linux上使用带有char的UTF-8,在Windows上使用带有wchar_t的UTF-16。我记得在Python参考实现中读到过这个诀窍,但是文章很旧了。我不确定现在是否仍然如此。

请查看Joel Spolsky关于Unicode的文章,以获取更详细的讨论,了解为什么charwchar_t在多字节字符集中不能保存字符。http://www.joelonsoftware.com/articles/Unicode.html - André Caron

1

在Linux上,您应该使用您所使用的框架提供的多字节字符串类。

我建议使用glibmm框架中的Glib::ustring,它将字符串存储在UTF-8编码中。 如果您的源文件是UTF-8编码的,则在代码中使用多字节字符串文字就像这样简单:

ustring alphabet("aąbcćdeęfghijklłmnńoóprsśtuwyzźż");

但是你不能使用char构建多字节字符的switch/case语句。我建议使用一系列的if。你可以使用Glibmm的gunichar,但它并不是很易读(你可以从维基百科上有关波兰字母表文章中的表格中获取字符的正确Unicode值):

#include <glibmm.h>
#include <iostream>

using namespace std;

int main()
{
        Glib::ustring alphabet("aąbcćdeęfghijklłmnńoóprsśtuwyzźż");
        int small_polish_vovels_with_diacritics_count = 0;
        for ( int i=0; i<alphabet.size(); i++ ) {
                switch (alphabet[i]) {
                        case 0x0105: // ą
                        case 0x0119: // ę
                        case 0x00f3: // ó
                                small_polish_vovels_with_diacritics_count++;
                                break;
                        default:
                                break;
                }
        }
        cout << "There are " << small_polish_vovels_with_diacritics_count
                << " small polish vovels with diacritics in this string.\n"; 
        return 0;
}

你可以使用以下方式进行编译:

g++ `pkg-config --cflags --libs glibmm-2.4` progname.cc -o progname

-1

std::string 用于 ASCII 字符串。由于您的波兰语字符串不适合,因此应使用 std::wstring


我听说在Linux上几乎不应该使用std::wstring,但我不太确定为什么。 - rhino
-1:std::string 没有定义特定的字符集,但在将多字节字符串存储在其中时需要注意一些边缘情况。请参见我对 jikv 答案的评论。 - André Caron
@rhino:请看我的回答以获取解释。 - André Caron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接