C++子字符串多字节字符
C++ substring multi byte characters
我有这个std::string,其中包含一些跨越多个字节的字符。
当我在这个字符串上做一个子字符串时,输出是无效的,因为当然,这些字符被计为 2 个字符。在我看来,我应该改用 wstring,因为它会将这些字符存储为一个元素而不是多个元素。
所以我决定将字符串复制到 wstring 中,但这当然没有意义,因为字符仍然被拆分为 2 个字符。这只会使情况变得更糟。
将字符串转换为 wstring 是否有一个好的解决方案,将特殊字符合并为 1 个元素而不是 2。
谢谢
更简单的版本。基于提供的解决方案 获取 UTF-8 编码标准::字符串的实际长度?作者:马塞洛·坎托斯
std::string substr(std::string originalString, int maxLength)
{
std::string resultString = originalString;
int len = 0;
int byteCount = 0;
const char* aStr = originalString.c_str();
while(*aStr)
{
if( (*aStr & 0xc0) != 0x80 )
len += 1;
if(len>maxLength)
{
resultString = resultString.substr(0, byteCount);
break;
}
byteCount++;
aStr++;
}
return resultString;
}
std::string
对象不是字符串,而是字节字符串。它根本没有所谓的"编码"概念。std::wstring
也是如此,除了它是一个 16 位值的字符串。
为了对需要寻址不同字符的文本执行操作(例如,当您想要获取子字符串时),您需要知道用于 std::string 对象的编码。
更新:既然您已经阐明了输入字符串是 UTF-8 编码的,您仍然需要决定用于输出std::wstring
的编码。UTF-16 浮现在脑海中,但这实际上取决于您将传递std::wstring
对象所需的 API。假设 UTF-16 是可以接受的,您有多种选择:
- 在Windows上,您可以使用
MultiByteToWideChar
函数;不需要额外的依赖项。 - UTF8-CPP 库声称为处理 UTF-* 编码字符串提供了一种轻量级解决方案。我自己从来没有尝试过,但我不断听到关于它的好消息。
- 在 Linux 系统上,使用 libiconv 库是很常见的。
- 如果您需要处理各种疯狂的编码,并且想要就编码而言成熟的alpha和omega单词,请查看ICU。
实际上只有两种可能的解决方案。 如果你正在这样做很多,在很远的距离上,你最好转换你的字符到单个元素编码,使用 wchar_t
(或int32_t
,或任何最合适的东西。 这不是一个简单的副本,会将每个单独的char
转换为目标类型,但 true转换函数,可识别多字节字符,以及将它们转换为单个元素。
对于偶尔使用或较短的序列,可以编写自己的序列用于前进 n
字节的函数。 对于 UTF-8,我使用以下方法:
inline size_t
size(
Byte ch )
{
return byteCountTable[ ch ] ;
}
template< typename InputIterator >
InputIterator
succ(
InputIterator begin,
size_t size,
std::random_access_iterator_tag )
{
return begin + size ;
}
template< typename InputIterator >
InputIterator
succ(
InputIterator begin,
size_t size,
std::input_iterator_tag )
{
while ( size != 0 ) {
++ begin ;
-- size ;
}
return begin ;
}
template< typename InputIterator >
InputIterator
succ(
InputIterator begin,
InputIterator end )
{
if ( begin != end ) {
begin = succ( begin, end, size( *begin ),
std::::iterator_traits< InputIterator >::iterator_category() ) ;
}
return begin ;
}
template< typename InputIterator >
size_t
characterCount(
InputIterator begin,
InputIterator end )
{
size_t result = 0 ;
while ( begin != end ) {
++ result ;
begin = succ( begin, end ) ;
}
return result ;
}
基于此,我编写了我的 utf8 子字符串函数:
void utf8substr(std::string originalString, int SubStrLength, std::string& csSubstring)
{
int len = 0, byteIndex = 0;
const char* aStr = originalString.c_str();
size_t origSize = originalString.size();
for (byteIndex=0; byteIndex < origSize; byteIndex++)
{
if((aStr[byteIndex] & 0xc0) != 0x80)
len += 1;
if(len >= SubStrLength)
break;
}
csSubstring = originalString.substr(0, byteIndex);
}
Unicode很难。
-
std::wstring
不是代码点的列表,而是wchar_t
的列表,它们的宽度是实现定义的(通常VC++为16位,gcc和clang为32位)。是的,这意味着它对可移植代码毫无用处... - 单个字符可以在多个代码点上编码(由于音调符号)
- 在某些语言中,两个不同的字符共同形成一个实际上不可分离的"单元"(例如,
LL
在西班牙语中被视为一个字母)。
所以......这有点难。
解决 3) 可能成本高昂(需要特定的语言/用法注释);解决 1) 和 2) 是绝对必要的...并且需要 Unicode 感知库或编写自己的代码(并且可能会出错)。
- 1)是微不足道的解决:编写从UTF-8到CodePoint的例程是微不足道的(CodePoint可以用
uint32_t
表示) - 2)更难,它需要一个变音符号列表,子例程必须知道永远不要在变音符号之前剪切(它们遵循它们限定的字符)
否则,您可能会在ICU中寻求什么。祝你好运找到它。
为简单起见,让我假设您的编码是 UTF-8。在这种情况下,我们会有一些字符占用多个字节,就像您的情况一样。然后你有 std::string,其中存储了这些 UTF-8 编码字符。现在你想用字符而不是字节来代替 substr()。我会编写一个将字符长度转换为字节长度的函数。对于 utf 8 的情况,它看起来像:
#define UTF8_CHAR_LEN( byte ) (( 0xE5000000 >> (( byte >> 3 ) & 0x1e )) & 3 ) + 1
int32 GetByteCountForCharCount(const char* utf8Str, int charCnt)
{
int ByteCount = 0;
for (int i = 0; i < charCnt; i++)
{
int charlen = UTF8_CHAR_LEN(*utf8Str);
ByteCount += charlen;
utf8Str += charlen;
}
return ByteCount;
}
所以,假设你想从第 7 个字符中 substr() 字符串。 没问题:
int32 pos = GetByteCountForCharCount(str.c_str(), 7);
str.substr(pos);
- 多字节到宽字符无法正常工作
- 如果使用多字节字符集,为什么TCHAR值会更改
- 当 NUL 字符被定义为字符串的一部分时,为什么 strlen() 不计算终止 NUL 字符的字节?
- 多字节字符'377777'如何工作?
- 找到最长的UTF-8序列,而无需打破多字节序列
- 如何在MFC多字节应用程序中显示西里尔文本?
- 从多字节字符集转换旧的Visual Studio C++项目
- 了解多字节/Unicode
- 在 linux/mac 中获取多字节字符的"char"
- 操作多字节字符的字符串
- Visual Studio 多字节字符到单个字节
- 多字节到宽字符将 (°) 度数符号转换为
- setw() 在包含 UTF-8 多字节字符/码位的字符串上输入错误的输出
- C++子字符串多字节字符
- 多字节到宽字符转换后,内存中存在临时副本
- 如何提取tar.gz,包括多字节字符和windows上禁止的字符
- 如何在mac上将多字节转换为宽字符
- Unicode字符或多字节字符:哪种类型更有效?为什么
- c++如何获取下一个多字节字符
- C++返回字符串中最常见字符的函数中的错误.多字节字符