用字符而不是字节进行子str

substr with characters instead of bytes

本文关键字:str 字节 字符      更新时间:2023-10-16

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

当我做一个substring(30,40)它返回"#Person Tätigkeitsdarstellung",从一个空格开始。我想它是在计算字节而不是字符。

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

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

感谢您的帮助!

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

一个简单的方法是使用 std::wstring . wstring使用的字符类型(wchar_t(至少与系统支持的最宽字符集一样宽。因此,如果系统支持足够宽的编码来表示具有单个代码单元的任何(非复合(unicode 字符,则字符串方法的行为将符合您的预期。目前utf-32已经足够宽了,并且被(大多数?(像操作系统这样的Unix支持。

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

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++至少在gcc-4.8中没有实现在c ++ 11中引入的<codecvt>。如果你不需要libc++,那么类似的功能可能在Boost.Locale中。

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