几天前偶尔看到有人发帖子问“如何自动识别判断url中的中文参数是GB2312还是Utf-8编码”
也拜读了wcwtitxu使用巨牛的正则表达式检测UTF8编码的算法。
使用无数或条件的正则表达式用起来却是性能不高。
刚好曾经在项目中有类似的需求,这里把处理思路和整理后的源代码贴出来供大家参考
先聊聊原理:
UTF8的编码规则如下表
UTF8 Encoding Rule
看起来很复杂,总结起来如下:
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
其实java的操作也类似,有时间再写个
分享到:
相关推荐
一、介绍 UTF-8 是一种在web应用中经常使用的一种 Unicode 字符的编码方式,使用 UTF-8 的好处在于它是一种变长的编码方式,对于 ...这个标记是可选的,因为UTF8字节没有顺序,所以它可以被用来检测一个字节流是否是UTF
db-utf8-转码器一个AC程序... 如果无法确定特定字符串的编码,则返回原始字节流。 将已转换和/或未转换的数据写回到同一行。 确认更新后记录转换。 清理内存和数据库连接,然后退出。 请注意,步骤6、7和8不是事务性的
如果文件或者数据流以非标准但普遍的"UTF-8引导字节" (0xef 0xbb 0xbf)开始,TinyXML会以UTF-8的方式来读取它。 如果包含有encoding="UTF-8"的声明被读取,那么TinyXML会以UTF-8的方式来读取它。 如果读取到没有指定...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
开发它是用于在UTF-8 Oracle实例中使用ASCII编码的Oracle 数据库中来正确的传输非ASCII字符。 Java模板语言 Beetl Beetl,是Bee Template Language的缩写,它绝不是简单的另外一种模板引擎,而是新一代的模板引擎,...
WinRAR 内部查看器能检测并显示 UTF-8 和 UTF-16 小端字节序编码的文件。 18. UTF-16 小端字节序编码被用于 RAR 和 WinRAR 日志文件 rar.log 中,所以 Unicode 文件名能在日志文件中正确存储。WinRAR 会自动...