在C / C ++中将UTF-8字符串存储在内存中的最佳方法是什么?

时间:2009-01-12 11:22:54

标签: c++ unicode

查看unicode standard,他们建议使用普通char来存储UTF-8编码的字符串。这是否与C ++和基本std::string一样正常工作,或者存在UTF-8编码可能产生问题的情况?

例如,在计算长度时,它可能与字节数不同 - 这应该如何处理?阅读标准,我可能很好地使用char数组进行存储,但我仍然需要自己编写像strlen等函数来处理编码文本,导致到目前为止正如我所理解的那样,标准例程只能是ASCII,或者是期望宽文字(16位或更多),这是unicode标准不推荐的。到目前为止,我发现有关编码内容的最佳来源是Joel's on Software上的帖子,但它没有解释我们可怜的C ++开发人员应该使用的内容:)

6 个答案:

答案 0 :(得分:5)

有一个名为“UTF8-CPP”的库,它允许您将UTF-8字符串存储在标准的std :: string对象中,并提供枚举和操作utf-8字符的附加函数。

我还没有测试过,所以我不知道它的价值,但我正在考虑自己使用它。

答案 1 :(得分:3)

ICU library(C,C ++,Java)的例子:

#include <iostream>
#include <unicode/unistr.h> // using ICU library

int main(int argc, char *argv[]) {
    // constructing a Unicode string
    UnicodeString ustr1("Привет"); // using platform's default codepage
    // calculating the length in characters, should be 6
    int ulen1=ustr1.length();
    // extracting encoded characters from a string
    int const bufsize=25;
    char encoded[bufsize];
    ustr1.extract(0,ulen1,encoded,bufsize,"UTF-8"); // forced UTF-8 encoding
    // printing the result
    std::cout << "Length of " << encoded << " is " << ulen1 << "\n";
    return 0;
}

建设像

$ g++ -licuuc -o icu-example{,.cc}

运行

$ ./icu-example
Length of Привет is 6

适用于Linux的GCC 4.3.2和libicu 3.8.1。请注意,无论系统区域是什么,它都以UTF-8打印。如果你的不是UTF-8,你将无法正确看到它。

答案 2 :(得分:2)

这取决于你想用UTF8字符串做什么。如果你感兴趣的只是读入和读出UTF8字符串,那么只要你设置了正确的语言环境,它就会起作用。我们已经做了一段时间了。我们有几个服务器进程对字符串不做任何事情。用户在Java中设置字符串并以UTF8形式到达,我们在标准c str缓冲区中处理它们。然后,我们将数据发送回Java,将其转换回来。

如果你想要UTF8字符的长度,那么你需要能够为你处理翻译的函数。

但你可以推出自己的例子utf8-strlen

答案 3 :(得分:2)

strlen计算第一个\ 0之前的非空字符数。在UTF-8中,该计数是一个合理的数字(使用的字节数),但计数不是字符数(一个UTF-8字符通常是1-4个字符)。 basic_string不存储\ 0,但它也保留字节数。

strcpy或basic_string copy ctor复制所有字节而不太仔细。

由于UTF_8的编码方式,查找子字符串工作正常。字符的第一个字节的允许值不同于第二个到第4个字节(前者永远不会以10xxxxxx开头,后者总是以后者开始)

获取子字符串很棘手 - 您如何指定位置?如果通过搜索ASCII文本标记(例如[和])找到了开始和结束,则没有问题。你只需要获得中间的字节,这也是一个有效的UTF8字符串。你不能对位置,甚至是相对偏移进行编码。即使+1字符的相对偏移也很难;这是多少字节?你最终会编写像SkipOneChar这样的函数。

答案 4 :(得分:1)

我们解决了什么:将UTF8存储在std :: string中。除了计算长度之外,您现在可以执行大多数操作。当您需要这样的操作时,使用UTF8-&gt; std :: wstring转换函数(例如boost :: from_utf8)转换为std :: wstring。

答案 5 :(得分:0)

来自UTF-8 and Unicode FAQ: C support for Unicode

#include <stdio.h>
#include <locale.h>

int main()
{
  if (!setlocale(LC_CTYPE, "")) {
    fprintf(stderr, "Can't set the specified locale! "
            "Check LANG, LC_CTYPE, LC_ALL.\n");
    return 1;
  }
  printf("%ls\n", L"Schöne Grüße");
  return 0;
}

同样来自here

  

好消息是,如果你使用   wchar_t*字符串和系列   与它们相关的功能,如   你是wprintfwcslenwcslcat   处理Unicode值。在里面   在C ++世界中,您可以使用std::wstring来实现   提供友好的界面。我唯一的   投诉是这些是32位(4   字节)字符,所以它们是内存   所有语言的猪。的原因   这个选择是它保证每一个   可以表示可能的角色   一个值。

PS。这可能是特定于Linux的。有一个ICU库来处理复杂的事情。