几天前偶尔看到有人发帖子问“如何自动识别判断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>
public static bool IsTextUTF8(ref byte[] inputStream)
{
    int encodingBytesCount = 0;
    bool allTextsAreASCIIChars = true;
 
    for (int i = 0; i < inputStream.Length; i++)
    {
        byte current = 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.
                return false;
            }
        }               
        else
        {
            // Following bytes, must start with 10.
            if ((current & 0xC0) == 0x80)
            {                       
                encodingBytesCount--;
            }
            else
            {
                // Invalid bits structure for UTF8 encoding rule.
                return false;
            }
        }
    }
 
    if (encodingBytesCount != 0)
    {
        // Invalid bits structure for UTF8 encoding rule.
        // Wrong following bytes count.
        return false;
    }
 
    // 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()]
public class EncodingHelperTest
{
    /// <summary>
    ///  Normal test for this method.
    ///</summary>
    [TestMethod()]
    public void IsTextUTF8Test()
    {
        for (int i = 0; i < 1000; i++)
        {
            List<Char> chars = new List<char>();
            chars.Add('中');
 
            List<UnicodeCategory> temp = new List<UnicodeCategory>();
            Random rd = new Random((int)(DateTime.Now.Ticks & 0x7FFFFFFF));
 
            for (int j = 0; j < 255; j++)
            {
                char ch = (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);
                }
            }
 
            string str = new string(chars.ToArray());
 
            byte[] inputStream = Encoding.UTF8.GetBytes(str);
            bool expected = true;
            bool actual;
            actual = EncodingHelper.IsTextUTF8(ref inputStream);
            Assert.AreEqual(expected, actual, string.Format("UTF8_Assert Fails at:{0}", str));
 
            inputStream = Encoding.GetEncoding(932).GetBytes(str);
            expected = false;
 
            actual = EncodingHelper.IsTextUTF8(ref inputStream);
            Assert.AreEqual(expected, actual, string.Format("ShiftJIS_Assert Fails at:{0}", str));
        }
    }
 
    /// <summary>
    ///   Check with All ASCII chars
    /// </summary>
    [TestMethod]
    public void IsTextUTF8Test_AllASCII()
    {
        string str = "ABCDEFGHKLHSJKLDFHJKLHAJKLSHJKLHAJKLSHDJKLAHSDJKLHAJKLSDHJKLASHDJKLHASJKLDHJKLASD";
 
        byte[] inputStream = Encoding.UTF8.GetBytes(str);
        bool expected = false;
        bool actual;
        actual = EncodingHelper.IsTextUTF8(ref inputStream);
        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编码的更多相关文章

  1. 检测字符串是否为UTF8编码

    /** * 检测字符串是否为UTF8编码 * @param string $str 被检测的字符串 * @return boolean */ function is_utf8($str){ $len ...

  2. 判断URL中的中文参数是GB2312还是Utf-8编码

    如两个URL字符串: &q=%E8%A3%99%E5%AD%90&style=grid&seller_type=taobao &q=%CE%D0%C2%D6%D4%F6 ...

  3. 检测UTF-8编码

    在PHP检测字符串是否是UTF-8编码的时候,很多人在使用mb_detect_encoding的时候,经常遇到检测不准的问题,下面的方法可以准确检测编码是否是UTF-8 function check_ ...

  4. ASP.NET中将导出的数据以UTF-8编码方式进行存储

      Response.Charset = "UTF-8"; Response.ContentEncoding = Encoding.UTF8; Response.AppendHea ...

  5. 【Java】如何检测、替换4个字节的utf-8编码(此范围编码包含emoji表情)

    > 参考的优秀文章 1.十分钟搞清字符集和字符编码 2.Java中byte与16进制字符串的互相转换 3.[异常处理]Incorrect string value: '\xF0\x90\x8D\ ...

  6. UTF-8编码中BOM的检测与删除[linux下命令]

    Posted on 2011-05-14 所谓BOM,全称是Byte Order Mark,它是一个Unicode字符,通常出现在文本的开头,用来标识字节序(Big/Little Endian),除此 ...

  7. 检测当前的语言环境是否使用了 UTF-8 编码(三篇文章:先用setlocale()设置编码,再用nl_langinfo()进行检测。locale对象可以使用langLocale.name() == "zh_CN"判断)

    C/C++程序中,locale(即系统区域设置,即国家或地区设置)将决定程序所使用的当前语言编码.日期格式.数字格式及其它与区域有关的设置,locale设置的正确与否将影响到程序中字符串处理(wcha ...

  8. Java检测文件是否UTF8编码

    介绍UTF-8编码规则 UTF-8 编码字符理论上可以最多到 6 个字节长, 然而 16 位 BMP 字符最多只用到 3 字节长. Bigendian UCS-4 字节串的排列顺序是预定的. 字节 0 ...

  9. 刨根究底字符编码之十一——UTF-8编码方式与字节序标记

    UTF-8编码方式与字节序标记 一.UTF-8编码方式 1. 接下来将分别介绍Unicode字符集的三种编码方式:UTF-8.UTF-16.UTF-32.这里先介绍应用最为广泛的UTF-8. 为满足基 ...

随机推荐

  1. 例说 AD中ROOM的使用

    从OrCAD中将网表导入之后,区别于从AD原理图中导入,笔者经过反复试验,发现在OrCAD中定义的种种区域属性,比如像Page,Class,Room,在AD中导入之后全部消失,这就意味着你本来按照模块 ...

  2. 小qyvlik 先看两个视频,和 QtQuick UI 问答

    http://edu.csdn.net/course/detail/1042 http://edu.csdn.net/course/detail/335 http://blog.csdn.net/qy ...

  3. C#进程间通讯技术-整理。

    原文:C#进程间通讯技术-整理. 扩展阅读:http://www.cnblogs.com/joye-shen/archive/2012/06/16/2551864.html 一.进程间通讯的方式 1) ...

  4. 【操作系统】进程间通信(C#)

    原文:[操作系统]进程间通信(C#) 08年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大学生活.此系列是对四年专业课程学习的回顾,索引参见:http://blog.csdn.net/xia ...

  5. 各类XML parser的比较

    基于以上的比较 再为公司的项目选择解析器的时候,我选择Xerces.准备把Qt自带的XML库给去掉. references: http://stackoverflow.com/questions/17 ...

  6. VS2010编译Qt程序失败------error LNK1123: 转换到 COFF 期间失败:

    error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏使用VS2010编译VC++项目的时候可能会出这个问题. 据说升级到SP1后可能问题解决,但是下载量太大,目前没有得到证实. ...

  7. VC++如何在程序中用代码注册和卸载ocx控件(代码)

    方法一:在dos或Windows命令行下运行:regsvr32 ocxname.ocx 注册 示例:regsvr32 netshare.ocx     //注册netshare.ocx控件regsvr ...

  8. poj2429:因数分解+搜索

    题意:给定gcd(a,b)和lcm(a,b) 求使得a+b最小的 a,b 思路:结合算数基本定理中 gcd lcm的质因子表示形式 把lcm(a,b)质因数分解 以后 通过dfs找到 a+b最小的a ...

  9. Linux远程访问windows时,出现"连接被对端重置"错误

    1.sudo apt-get install rdesktop 需要下载 152 kB 的软件包.       解压缩后会消耗掉 512 kB 的额外空间. 2.运行时出现错误 root@oskey- ...

  10. 【转】FLV视频封装格式详解

    Overview Flash Video(简称FLV),是一种流行的网络格式.目前国内外大部分视频分享网站都是采用的这种格式. File Structure 从整个文件上开看,FLV是由The FLV ...