检测字节流是否是UTF8编码
几天前偶尔看到有人发帖子问“如何自动识别判断url中的中文参数是GB2312还是Utf-8编码”
也拜读了wcwtitxu使用巨牛的正则表达式检测UTF8编码的算法。
使用无数或条件的正则表达式用起来却是性能不高。
刚好曾经在项目中有类似的需求,这里把处理思路和整理后的源代码贴出来供大家参考
先聊聊原理:
UTF8的编码规则如下表

看起来很复杂,总结起来如下:
ASCII码(U+0000 - U+007F),不编码
其余编码规则为
•第一个Byte二进制以形式为n个1紧跟个0 (n >= 2), 0后面的位数用来存储真正的字符编码,n的个数说明了这个多Byte字节组字节数(包括第一个Byte)
•结下来会有n个以10开头的Byte,后6个bit存储真正的字符编码。
因此对整个编码byte流进行分析可以得出是否是UTF8编码的判断。
根据这个规则,我给出的C#代码如下:
| /// <summary>///   Determines whether the given <paramref name="inputStream"/>is UTF8 encoding bytes./// </summary>/// <param name="inputStream">///    The input stream.///  </param>/// <returns>///   <see langword="true"/> if given bystes stream is in UTF8 encoding; otherwise, <see langword="false"/>./// </returns>/// <remarks>///   All ASCII chars will regards not UTF8 encoding./// </remarks>publicstaticboolIsTextUTF8(refbyte[] inputStream){    intencodingBytesCount = 0;    boolallTextsAreASCIIChars = true;    for(inti = 0; i < inputStream.Length; i++)    {        bytecurrent = inputStream[i];        if((current & 0x80) == 0x80)        {                                allTextsAreASCIIChars = false;        }        // First byte        if(encodingBytesCount == 0)        {            if((current & 0x80) == 0)            {                // ASCII chars, from 0x00-0x7F                continue;            }            if((current & 0xC0) == 0xC0)            {                encodingBytesCount = 1;                current <<= 2;                // More than two bytes used to encoding a unicode char.                // Calculate the real length.                while((current & 0x80) == 0x80)                {                    current <<= 1;                    encodingBytesCount++;                }            }                                else            {                // Invalid bits structure for UTF8 encoding rule.                returnfalse;            }        }                        else        {            // Following bytes, must start with 10.            if((current & 0xC0) == 0x80)            {                                        encodingBytesCount--;            }            else            {                // Invalid bits structure for UTF8 encoding rule.                returnfalse;            }        }    }    if(encodingBytesCount != 0)    {        // Invalid bits structure for UTF8 encoding rule.        // Wrong following bytes count.        returnfalse;    }    // Although UTF8 supports encoding for ASCII chars, we regard as a input stream, whose contents are all ASCII as default encoding.    return!allTextsAreASCIIChars;} | 
再附上单元测试代码:
| /// <summary>///This is a test class for EncodingHelperTest and is intended///to contain all EncodingHelperTest Unit Tests///</summary>[TestClass()]publicclassEncodingHelperTest{    /// <summary>    ///  Normal test for this method.    ///</summary>    [TestMethod()]    publicvoidIsTextUTF8Test()    {        for(inti = 0; i < 1000; i++)        {            List<Char> chars = newList<char>();            chars.Add('中');            List<UnicodeCategory> temp = newList<UnicodeCategory>();            Random rd = newRandom((int)(DateTime.Now.Ticks & 0x7FFFFFFF));            for(intj = 0; j < 255; j++)            {                charch = (char)rd.Next(0xFFFF);                UnicodeCategory uc = System.Globalization.CharUnicodeInfo.GetUnicodeCategory(ch);                if(uc == UnicodeCategory.Surrogate || // Single surrogate could not be encoding correctly.                    uc == UnicodeCategory.PrivateUse || // Private use blocks should be excluded.                    uc == UnicodeCategory.OtherNotAssigned                    )                {                    j--;                }                else                {                    chars.Add(ch);                    temp.Add(uc);                }            }            stringstr = newstring(chars.ToArray());            byte[] inputStream = Encoding.UTF8.GetBytes(str);            boolexpected = true;             boolactual;            actual = EncodingHelper.IsTextUTF8(refinputStream);            Assert.AreEqual(expected, actual, string.Format("UTF8_Assert Fails at:{0}", str));            inputStream = Encoding.GetEncoding(932).GetBytes(str);            expected = false;            actual = EncodingHelper.IsTextUTF8(refinputStream);            Assert.AreEqual(expected, actual, string.Format("ShiftJIS_Assert Fails at:{0}", str));        }    }    /// <summary>    ///   Check with All ASCII chars    /// </summary>    [TestMethod]    publicvoidIsTextUTF8Test_AllASCII()    {        stringstr = "ABCDEFGHKLHSJKLDFHJKLHAJKLSHJKLHAJKLSHDJKLAHSDJKLHAJKLSDHJKLASHDJKLHASJKLDHJKLASD";        byte[] inputStream = Encoding.UTF8.GetBytes(str);        boolexpected = false;        boolactual;        actual = EncodingHelper.IsTextUTF8(refinputStream);        Assert.AreEqual(expected, actual, string.Format("UTF8_Assert Fails at:{0}", str));    }} | 
另:
如果是判断一个文件是否使用了UTF8编码,不一定非用这种方法,因为通常以UTF8格式保存的文件最初两个字符是BOM头,标示该文件使用了UTF8编码。
参考:
维基百科:http://en.wikipedia.org/wiki/UTF-8
http://www.cnblogs.com/powertoolsteam/archive/2010/09/20/1831638.html
检测字节流是否是UTF8编码的更多相关文章
- 检测字符串是否为UTF8编码
		/** * 检测字符串是否为UTF8编码 * @param string $str 被检测的字符串 * @return boolean */ function is_utf8($str){ $len ... 
- 判断URL中的中文参数是GB2312还是Utf-8编码
		如两个URL字符串: &q=%E8%A3%99%E5%AD%90&style=grid&seller_type=taobao &q=%CE%D0%C2%D6%D4%F6 ... 
- 检测UTF-8编码
		在PHP检测字符串是否是UTF-8编码的时候,很多人在使用mb_detect_encoding的时候,经常遇到检测不准的问题,下面的方法可以准确检测编码是否是UTF-8 function check_ ... 
- ASP.NET中将导出的数据以UTF-8编码方式进行存储
		Response.Charset = "UTF-8"; Response.ContentEncoding = Encoding.UTF8; Response.AppendHea ... 
- 【Java】如何检测、替换4个字节的utf-8编码(此范围编码包含emoji表情)
		> 参考的优秀文章 1.十分钟搞清字符集和字符编码 2.Java中byte与16进制字符串的互相转换 3.[异常处理]Incorrect string value: '\xF0\x90\x8D\ ... 
- UTF-8编码中BOM的检测与删除[linux下命令]
		Posted on 2011-05-14 所谓BOM,全称是Byte Order Mark,它是一个Unicode字符,通常出现在文本的开头,用来标识字节序(Big/Little Endian),除此 ... 
- 检测当前的语言环境是否使用了 UTF-8 编码(三篇文章:先用setlocale()设置编码,再用nl_langinfo()进行检测。locale对象可以使用langLocale.name() == "zh_CN"判断)
		C/C++程序中,locale(即系统区域设置,即国家或地区设置)将决定程序所使用的当前语言编码.日期格式.数字格式及其它与区域有关的设置,locale设置的正确与否将影响到程序中字符串处理(wcha ... 
- Java检测文件是否UTF8编码
		介绍UTF-8编码规则 UTF-8 编码字符理论上可以最多到 6 个字节长, 然而 16 位 BMP 字符最多只用到 3 字节长. Bigendian UCS-4 字节串的排列顺序是预定的. 字节 0 ... 
- 刨根究底字符编码之十一——UTF-8编码方式与字节序标记
		UTF-8编码方式与字节序标记 一.UTF-8编码方式 1. 接下来将分别介绍Unicode字符集的三种编码方式:UTF-8.UTF-16.UTF-32.这里先介绍应用最为广泛的UTF-8. 为满足基 ... 
随机推荐
- android 之 百度地图
			简介 百度地图Android定位SDK为基于移动客户端开发LBS应用提供基础定位能力. 功能介绍 功能介绍: 地图展示:包括2D图.卫星图.3D图地图展示. 地图操作:提供控制平移.缩放.底图旋转.变 ... 
- 【转】解决java.lang.IllegalStateException: The content of the adapter has changed but ListView...的问题
			原文网址:http://blog.csdn.net/ueryueryuery/article/details/20607845 我写了一个Dialog,Dialog中有一个ListView,想要点Li ... 
- linux内核--中断和中断处理(一)
			让硬件在需要的时候再向内核发出信号.这就是中断机制,先讨论中断,进而讨论内核如何使用所谓的中断处理函数处理对应的中断. 一.中断 1)中断 中断使得硬件得以发出通知给处理器.例如, ... 
- Linux中open函数以及退出进程的函数
			open函数的flag详解1 读写权限:O_RDONLY O_WRONLY O_RDWR (1)linux中文件有读写权限,我们在open打开文件时也可以附带一定的权限说明 (譬如O_RDONLY就表 ... 
- c语言for语句
			首先呢 for语句是由4部分组成 for(表达式1;表达式2;表达式3) 循环体: 注意 1:循环中的表达式用;隔开 表达式1通常用来呢赋初值 表达式2通常用来循环控制也就是循环条件 表达式3通常就是 ... 
- 图片实时预览JSP加js
			<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ... 
- Python一日一练05----怒刷点击量
			功能 自己主动获取CSDN文章列表,并对每篇文章添加点击量. 源代码 import urllib.request import re import time import random from bs ... 
- 深入浅出理解iOS经常使用的正則表達式—基础篇[Foundation]
			參考资料:cocoachina的zys475481075的文章 几个单词 Regular ['regjʊlə]adj. 定期的:有规律的 Expression[ɪk'spreʃ(ə)n; ek-] n ... 
- OC教程10-NSNumber具体
			NSNumber简单介绍 NSNumber是数字的对象形式,由于在OC的数组和字典中仅仅同意存放对象,所以我们有时候须要转化 我们普通的类型是 123 那么 NSNumber类型的是 @123, ... 
- Samba-ADS/WINBIND
			Samba Security = ADShttp://www.justlinux.com/forum/showt...hreadid=118288 Winbindhttp://www.justlinu ... 
