我从TCP服务器接收到一个字节流缓冲区,其中可能包含形成Unicode字符的多字节字符。我想知道是否总有一种方法可以检查BOM来检测这些字符,否则你会怎么做?
如果你知道数据是UTF-8编码,那么你只需要检查高位:
或者,如果你需要区分前导/尾随字节:
在UTF-8中,任何开头为8位的字节都属于多字节码点。因此,基本上检查每个字节的(0x80 & c)!=0
就是最简单的方法。
让我实现dan04的答案。
从现在开始,我使用C++14。如果你只能使用旧版本的C++,你必须将二进制字面值(例如0b10
)重写为整型字面值(例如2
)。
int is_utf8_character(unsigned char c) { //casts to `unsigned char` to force logical shifts
if ((c >> 7) == 0b1) {
if ((c >> 6) == 0b10) {
return 2; //2nd, 3rd or 4th byte of a utf-8 character
} else {
return 1; //1st byte of a utf-8 character
}
} else {
return 0; //a single byte character (not a utf-8 character)
}
}
using namespace std;
#include <iostream>
namespace N {
int is_utf8_character(unsigned char c) { //casts to `unsigned char` to force logical shifts
if ((c >> 7) == 0b1) {
if ((c >> 6) == 0b10) {
return 2; //2nd, 3rd or 4th byte of a utf-8 character
} else {
return 1; //1st byte of a utf-8 character
}
} else {
return 0; //a single byte character (not a utf-8 character)
}
}
unsigned get_string_length(const string &s) {
unsigned width = 0;
for (int i = 0; i < s.size(); ++i) {
if (is_utf8_character(s[i]) != 2) {
++width;
}
}
return width;
}
unsigned get_string_display_width(const string &s) {
unsigned width = 0;
for (int i = 0; i < s.size(); ++i) {
if (is_utf8_character(s[i]) == 0) {
width += 1;
} else if (is_utf8_character(s[i]) == 1) {
width += 2; //We assume a multi-byte character consumes double spaces than a single-byte character.
}
}
return width;
}
}
int main() {
const string s = "こんにちはhello"; //"hello" is "こんにちは" in Japanese.
for (int i = 0; i < s.size(); ++i) {
cout << N::is_utf8_character(s[i]) << " ";
}
cout << "\n\n";
cout << " Length: " << N::get_string_length(s) << "\n";
cout << "Display Width: " << N::get_string_display_width(s) << "\n";
}
1 2 2 1 2 2 1 2 2 1 2 2 1 2 2 0 0 0 0 0
Length: 10
Display Width: 15
检测多字节字符有很多方法,但不幸的是...没有一种是可靠的。
如果这是一个网络请求返回的结果,请检查头部信息,因为Content-Type头部通常会指示页面编码(这可以表明多字节字符是否存在)。
您也可以检查BOM(字节顺序标记),因为它们是无效字符,正常文本中不应该出现,因此检查一下是否存在也无妨。然而,它们是可选的,并且许多情况下可能不存在(取决于实现、配置等)。
BOM通常是可选的。如果您从接收多字节字符的服务器接收数据,它可能会假定您知道这一点,并保存2个字节的BOM。您是否正在寻找一种方法来确定您接收到的数据是否可能是多字节字符串?