【问题标题】:substr with characters instead of bytes带有字符而不是字节的 substr
【发布时间】:2014-09-26 18:50:15
【问题描述】:

假设我有一个string s = "101870002PTäPO PVä #Person Tätigkeitsdarstellung 001100001&0111010101101870100092001000010"

当我执行substring(30,40) 时,它会返回以空格开头的“#Person Tätigkeitsdarstellung”。 我猜它是在计算字节而不是字符。

通常字符串的大小为 110,当我执行 s.length()s.size() 时,由于 3 个特殊字符,它返回 113。

我想知道是否有办法避免在返回值的开头出现这个空白。

感谢您的帮助!

【问题讨论】:

  • 不是字节,也不是直接,而是char。如果你对存储在std::string中的字符串进行了变长编码,则必须自己处理。
  • Normally the size of the string is 110 and when I do a s.length() or s.size() it returns 113 because of the 3 special characters. 那么这意味着字符串不是 110个字符,而是113个字符。 size() 函数不会说谎。另外,这些“特殊字符”是什么?回车,控制字符,...?
  • s.length() 给我 110 我再加一个 ä 然后给我 111 再加一个 # 然后它给我 112 再加一个 & 猜猜它会返回什么,惊喜 113。你能提供有关您的机器和 ide 的信息,也许这些是导致问题的原因。但是如果您想要我可以编写一个函数,如果您的不起作用,我可以使用 s.substr() 做同样的工作。
  • @PaulMcKenzie 我所说的特殊字符是德语字符。
  • @PaulMcKenzie size 函数不会说谎,但它也不会返回字符串中的字符数;只有char 的数量。

标签: c++ string substring special-characters substr


【解决方案1】:

在 utf-8 中,代码点(字符)ä 由两个代码单元组成(在 utf-8 中为 1 个字节)。 C++ 不支持将字符串视为代码点序列。因此,就标准库而言,std::string("ä").size() 为 2。

一个简单的方法是使用std::wstringwstring 使用的字符类型 (wchar_t) 至少与系统支持的最宽字符集一样宽。因此,如果系统支持足够宽的编码以用单个代码单元表示任何(非复合)unicode 字符,那么字符串方法的行为将与您预期的一样。目前 utf-32 足够宽,并且被(大多数?)unix 等操作系统支持。

需要注意的是,Windows 仅支持 utf-16 而不是 utf-32,因此如果您选择 wstring 方法并将您的程序移植到 Windows 并且您的程序的用户尝试使用超过2 字节宽,则每个代码点一个代码单元的假设不成立。

wstring 方法也不考虑控制或复合字符。

这是一个小测试代码,它将包含多字节 utf-8 字符 ästd::string 转换为 wstring

string foo("ä"); // read however you want
wstring_convert<codecvt_utf8<wchar_t>> converter;
wstring wfoo = converter.from_bytes(foo.data());
cout << foo.size() << endl; // 2 on my system
cout << wfoo.size() << endl; // 1 on my system

不幸的是,libstdc++ 没有实现&lt;codecvt&gt;,它至少从 gcc-4.8 开始在 c++11 中引入。如果你不需要 libc++,那么类似的功能可能在 Boost.Locale 中。

或者,如果您希望将代码移植到不支持 utf-32 的系统,您可以继续使用 std::string 并使用外部库进行迭代和计数等。这是一个:http://utfcpp.sourceforge.net/ 和另一个:http://site.icu-project.org/。我相信这是推荐的方法。

【讨论】:

  • 并非所有字符都可以用 Unicode 中的单个代码点表示。根据他正在做的事情(语言等),他可能只使用 UTF-16,忽略基本编码平面之外的复合字符或字符,或者他可能必须处理 UTF-32 中的复合字符。 (关于 UTF-16 与 UTF-32:Windows 和 AIX 是 UTF-16,Java 也是。大多数其他 Unices 是 UTF-32,尽管可能仍然支持早期宽字符编码的浮动。)跨度>
  • 他可能还想看看ICU,据说它非常完整。
  • @JamesKanze,我刚刚写了一个编辑,在您的评论中提到了复合字符的问题,即使是 utf-32 也是如此。
  • @user2079303 我正在使用 getline(basic_istream&, string&); 从文件中读取字符串我已经读到使用 wstring 太复杂了,无法在 linux 中使用!
  • @user2079303 感谢您提供有用的信息。我已经尝试过 utf8 外部库,它为我提供了正确的搅拌长度,但找不到一种方法来获取我可以使用 substr 的正确编码字符串。此外,我无法使用上面的代码部分转换为 wstring,make 抱怨“'wstring_convert' 未在此范围内声明”。 wstring 当我做某事时起作用:wstring str = L“mystring”,但我正在尝试转换一个字符串变量。
猜你喜欢
  • 2010-12-12
  • 1970-01-01
  • 1970-01-01
  • 2021-06-22
  • 2010-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多