过滤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