检测字节流是否是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>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编码的更多相关文章
- 检测字符串是否为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. 为满足基 ...
随机推荐
- EBS服务器管理
EBS 服务的重启 停止Oracle Applications 服务的顺序为:停止应用产品相关服务,再停止数据库相关服务: 启动Oracle Applications 服务的顺序为:启动数据库相关服务 ...
- StoryBoard 加入一个自定义View
1. 建一个 UIView的子类(MyView.h/MyView.m) 2. 建一个 View类型的XIB 3. 把xib的file‘s owner设为MyView 4. 在.h文件里加上 @prop ...
- Javascript:字符串分割split()妙用
概述: split() 方法将字符串分割为字符串数组,并返回此数组 语法格式: stringObject.split(separator,limit) 参数说明: 注意:如果把空字符串 (" ...
- jQuery的ajax jsonp跨域请求
了解:ajax.json.jsonp.“跨域”的关系 要弄清楚以上ajax.json.jsonp概念的关系,我觉得弄清楚ajax是“干什么的”,“怎么实现的”,“有什么问题”,“如果解决存在的问题”等 ...
- 关于时间的操作(JavaScript版)——年月日三级级联(默认依次显示请选择年、请选择月和请选择日)
这篇博客和前一篇博客基本同样,仅仅是显示的默认值不同: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN&quo ...
- Hexo博客搭建图文教程
准备 你需要准备好以下软件: Node.js环境 Git Windows 配置Node.js环境 下载Node.js安装文件: Windows Installer 32-bit Windows Ins ...
- 基于akka实现简单的主从框架
========================Master============================== package com.scala.akka.rpc.demo2 import ...
- Stm32高级定时器(四)
Stm32高级定时器(四) 1 编码器接口模式 1.1 编码器原理 什么是正交?如果两个信号相位相差90度,则这两个信号称为正交.由于两个信号相差90度,因此可以根据两个信号哪个先哪个后来判断方向.根 ...
- python-线程、进程、协程
进程 && 线程 进程:是内存中的一个独立的句柄,我们可以理解为一个应用程序在内存中就是一个进程. 各个进程之间是内存相互独立,不可共享的 线程:每个应用运行之后就会对应启动一个主线程 ...
- C# 中文转拼音类
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SU { ...