我的std :: string是utf-8编码所以很明显,str.length()返回错误的结果.
我发现了这些信息,但我不确定如何使用它来执行此操作:
以下字节序列用于表示字符.要使用的序列取决于字符的UCS代码编号:
Run Code Online (Sandbox Code Playgroud)0x00000000 - 0x0000007F: 0xxxxxxx 0x00000080 - 0x000007FF: 110xxxxx 10xxxxxx 0x00000800 - 0x0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 0x00010000 - 0x001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
如何找到UTF-8编码的std :: string的实际长度?谢谢
Mar*_*tos 63
计算所有第一个字节(与10xxxxxx不匹配的字节).
int len = 0;
while (*s) len += (*s++ & 0xc0) != 0x80;
Run Code Online (Sandbox Code Playgroud)
use*_*185 20
C++对编码一无所知,因此您不能指望使用标准函数来执行此操作.
标准库确实不承认字符编码的存在,在语言环境的形式.如果您的系统支持语言环境,则可以非常轻松地使用标准库来计算字符串的长度.在下面的示例代码中,我假设您的系统支持语言环境en_US.UTF-8.如果我编译代码并将其作为"./a.outソニーSony"执行,则输出结果是有13个char值和7个字符.所有这些都没有提及UTF-8字符代码的内部表示或必须使用第三方库.
#include <clocale>
#include <cstdlib>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
string str(argv[1]);
unsigned int strLen = str.length();
cout << "Length (char-values): " << strLen << '\n';
setlocale(LC_ALL, "en_US.utf8");
unsigned int u = 0;
const char *c_str = str.c_str();
unsigned int charCount = 0;
while(u < strLen)
{
u += mblen(&c_str[u], strLen - u);
charCount += 1;
}
cout << "Length (characters): " << charCount << endl;
}
Run Code Online (Sandbox Code Playgroud)
小智 8
这是一个幼稚的实现,但了解它是如何完成的应该对您有所帮助:
std::size_t utf8_length(std::string const &s) {
std::size_t len = 0;
std::string::const_iterator begin = s.begin(), end = s.end();
while (begin != end) {
unsigned char c = *begin;
int n;
if ((c & 0x80) == 0) n = 1;
else if ((c & 0xE0) == 0xC0) n = 2;
else if ((c & 0xF0) == 0xE0) n = 3;
else if ((c & 0xF8) == 0xF0) n = 4;
else throw std::runtime_error("utf8_length: invalid UTF-8");
if (end - begin < n) {
throw std::runtime_error("utf8_length: string too short");
}
for (int i = 1; i < n; ++i) {
if ((begin[i] & 0xC0) != 0x80) {
throw std::runtime_error("utf8_length: expected continuation byte");
}
}
len += n;
begin += n;
}
return len;
}
Run Code Online (Sandbox Code Playgroud)
您可能应该采纳Omry的建议,并为此寻找一个专门的库。就是说,如果您只是想了解执行此操作的算法,请在下面发布。
基本上,您可以将字符串转换为宽元素格式,例如wchar_t。请注意,这wchar_t存在一些可移植性问题,因为wchar_t其大小因平台而异。在Windows上wchar_t为2个字节,因此非常适合表示UTF-16。但是在UNIX / Linux上,它是四个字节,因此用于表示UTF-32。因此,对于Windows,仅当您不包括0xFFFF以上的任何Unicode代码点时,此方法才有效。对于Linux,您可以在中包含整个代码点范围wchar_t。(幸运的是,使用C ++ 0x Unicode字符类型可以缓解此问题。)
注意了这一警告之后,您可以使用以下算法创建转换函数:
template <class OutputIterator>
inline OutputIterator convert(const unsigned char* it, const unsigned char* end, OutputIterator out)
{
while (it != end)
{
if (*it < 192) *out++ = *it++; // single byte character
else if (*it < 224 && it + 1 < end && *(it+1) > 127) {
// double byte character
*out++ = ((*it & 0x1F) << 6) | (*(it+1) & 0x3F);
it += 2;
}
else if (*it < 240 && it + 2 < end && *(it+1) > 127 && *(it+2) > 127) {
// triple byte character
*out++ = ((*it & 0x0F) << 12) | ((*(it+1) & 0x3F) << 6) | (*(it+2) & 0x3F);
it += 3;
}
else if (*it < 248 && it + 3 < end && *(it+1) > 127 && *(it+2) > 127 && *(it+3) > 127) {
// 4-byte character
*out++ = ((*it & 0x07) << 18) | ((*(it+1) & 0x3F) << 12) |
((*(it+2) & 0x3F) << 6) | (*(it+3) & 0x3F);
it += 4;
}
else ++it; // Invalid byte sequence (throw an exception here if you want)
}
return out;
}
int main()
{
std::string s = "\u00EAtre";
cout << s.length() << endl;
std::wstring output;
convert(reinterpret_cast<const unsigned char*> (s.c_str()),
reinterpret_cast<const unsigned char*>(s.c_str()) + s.length(), std::back_inserter(output));
cout << output.length() << endl; // Actual length
}
Run Code Online (Sandbox Code Playgroud)
该算法不是完全通用的,因为InputIterator需要为无符号字符,因此您可以将每个字节解释为具有0到0xFF之间的值。OutputIterator是通用的(只是您可以使用std :: back_inserter而不用担心内存分配),但是它用作通用参数是有限的:基本上,它必须输出到足够大的元素数组来表示一个UTF-16或UTF-32字符,例如wchar_t,uint32_t或的C ++ 0x char32_t类型。另外,我没有包含转换大于4个字节的字符字节序列的代码,但是您应该从发布的内容中了解算法的工作原理。
另外,如果只想计算字符数,而不是输出到新的宽字符缓冲区,则可以修改算法以包括计数器而不是OutputIterator。或更妙的是,只需使用Marcelo Cantos的答案来计算首字节。
| 归档时间: |
|
| 查看次数: |
26274 次 |
| 最近记录: |