测试char *字符串是否包含多字节字符

问题描述 投票:5回答:5

我从TCP服务器收到一个字节流缓冲区,其中可能包含形成Unicode字符的多字节字符。我想知道是否总有一种方法可以检查BOM以检测那些字符,否则您想怎么做?

c++ unicode multibyte
5个回答
9
投票

如果您知道数据是UTF-8,则只需检查高位:

  • 0xxxxxxx =单字节ASCII字符
  • 1xxxxxxx =多字节字符的一部分

或者,如果您需要区分前导/后继字节:

  • 10xxxxxx =多字节字符的第二,第三或第四字节
  • 110xxxxx = 2字节字符的第一个字节
  • 1110xxxx = 3字节字符的第一个字节
  • 11110xxx = 4字节字符的第一个字节

2
投票

[有很多检测多字节字符的方法,不幸的是……它们都不可靠。

如果返回的是Web请求,请检查标题,因为Content-Type标题通常会指示页面编码(可以表示多字节字符显示)。

您还可以检查BOM表,因为它们是无效字符,因此无论如何它们都不会出现在普通文本中,因此查看它们是否存在也不会受到伤害。但是,它们是可选的,并且很多时候都不会出现(取决于实现方式,配置等)。


1
投票

BOM通常是可选的。如果您从中接收的服务器正在提供多字节字符,则它可能会假定您知道这一点,并为BOM保存2个字节。您是否正在要求一种方法来判断接收到的数据是否可能是多字节字符串?


1
投票

在UTF-8中,任何具有第8位的内容都是多字节代码点的一部分。因此,基本上检查每个字节的(0x80 & c)!=0是执行此操作的简单方法。


0
投票

让我实施dan04's answer

此后,我使用C ++ 14。如果您只能使用旧版本的C ++,则必须将binary literals(例如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
© www.soinside.com 2019 - 2024. All rights reserved.