过滤4字节及以上的字符c++实现

这个是根据php的一个版本改的,用来处理utf-8编码的多字节字符,比如中文,俄文等等。

#include <iostream>
#include <string>

int strip4ByteChars(const std::string str, std::string &ot);
unsigned char ord(int ch);

int main() {
    std::string str = "Esto es una prueba lalalala así que la llenaré de ÑÑÑÑÑÑ así y también de ÇÇÇÇÇÇÇÇ y algunos acentos en francés del tipo télévision, évenement, ouvrière, même, hôpital, juïf o âge.";
//    std::string str = "abcdefg АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩъыьЭЮЯ 你好世界!";
    std::string ret;
    if( strip4ByteChars(str, ret) == 0 ) {
        std::cout << str << std::endl << std::endl;
        std::cout << ret << std::endl;
    } else {
        std::cout << "error!" << std::endl;
    }
    return 0;
}

/**
 * 处理特殊字符串
 * @param string $str
 */
int strip4ByteChars(const std::string str, std::string &ot) {
    int len = str.length();
    unsigned char v,v2,v3;
    for (int i = 0; i < len; ) {
        v = ord(str[i]);
        if (v == 0x09 || v == 0x0A || (v < 0x80 && v >= 0x20)) { // 单字节
            ot += v;
            i += 1;
        } else if (v >= 0xC2 && v <= 0xDF) { // 双字节
            v2 = ord(str[i + 1]);
            if (v2 >= 80 && v2 <= 0xBF) {
                ot += v;
                ot += v2;
                i += 2;
            } else {
                ++i;
            }
        } else if (v == 0xE0) { // 三字节
            v2 = ord(str[i + 1]);
            v3 = ord(str[i + 2]);
            if (v2 >= 0xA0 && v2 <= 0xBF && v3 >= 0x80 && v3 <= 0xBF) {
                ot += v;
                ot += v2;
                ot += v3;
                i += 3;
            } else {
                ++i;
            }
        } else if (v == 0xED) { // 三字节
            v2 = ord(str[i + 1]);
            v3 = ord(str[i + 2]);
            if (v2 >= 0x80 && v2 <= 0x9F && v3 >= 0x80 && v3 <= 0xBF) {
                ot += v;
                ot += v2;
                ot += v3;
                i += 3;
            } else {
                i ++;
            }
        } else if (v >= 0xE1 && v <= 0xEF && v != 0xED) { // 三字节
            v2 = ord(str[i + 1]);
            v3 = ord(str[i + 2]);
            if (v2 >= 0x80 && v2 <= 0xBF && v3 >= 0x80 && v3 <= 0xBF) {
                ot += v;
                ot += v2;
                ot += v3;
                i += 3;
            } else {
                i ++;
            }
        } else if (v >= 0xF1 && v <= 0xF4) { // 四字节
            i += 4;
        } else { // 四字节以上
            i ++;
        }
    }

    return 0;
}
// 字符转ascii码,返回值为无符号int
unsigned char ord(int ch) {
    unsigned char ret;
    ret = ch & 0xff;
    return ret;
}

多字节字符的二进制表示如下:

Unicode符号范围      | UTF-8编码方式
(十六进制)           | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

以双字节字符为例110xxxxx 10xxxxxx

使用下标访问时每次访问一个字节,这时候双字节字符会被分开访问,如上的双字节将会分为110xxxxx和10xxxxxx,使用int保存时,单字节会自动补齐为当前系统中int需要的字节数,补齐规则跟系统有关,带符号数通常是按照符号位的值补齐,由于这两个字节的最高位都是1,以int为4字节为例,这两个字节在实际访问时就会变成:

11111111 11111111 11111111 110xxxxx 和 11111111 11111111 11111111 10xxxxxx

这样如果直接使用这两个值就会得到一个负数,而且远远超出了ascii码的表示范围,而我们真正需要的只是这两个int的地8位,所以使用

ret = ch & 0xff;

取出低8位,又因为ascii码没有负数,所以应该用unsigned char表示。

参考文件:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

posted @ 2017-02-21 11:04  lrxing  阅读(935)  评论(0编辑  收藏  举报