标题: 用VBS判断无BOM头的文件是否UTF-8编码
作者: Demon
链接: http://demon.tw/programming/vbs-validate-utf8.html
版权: 本博客的所有文章,都遵守“署名-非商业性使用-相同方式共享 2.5 中国大陆”协议条款。
在 VBS 贴吧看到吧主发的一个《如何区别无BOM头的UTF-8和GBK?》的贴子,故为此文。这种问题都解决不了,VBS 吧主的水平也不过如此。
字节顺序记号(英语:byte-order mark,BOM)是位于码点U+FEFF的统一码字符的名称。当以UTF-16或UTF-32来将UCS/统一码字符所组成的字符串编码时,这个字符被用来标示其字节序。它常被用来当做标示文件是以UTF-8、UTF-16或UTF-32编码的记号。
更多关于 BOM 的资料请自己阅读维基百科。
批处理之家有个《VBS版文件编码识别、转换工具(GB2312、UTF-8、Unicode、BIG5)》的帖子,其中检测文件编码的 CheckCode.vbs 是这么写的:
Function CheckCode (Usage) Dim slz set slz = CreateObject("Adodb.Stream") slz.Type = 1 slz.Mode = 3 slz.Open slz.Position = 0 slz.Loadfromfile file Bin=slz.read(2) if AscB(MidB(Bin,1,1))=&HEF and AscB(MidB(Bin,2,1))=&HBB Then Codes="UTF-8" elseif AscB(MidB(Bin,1,1))=&HFF and AscB(MidB(Bin,2,1))=&HFE Then Codes="Unicode" else Codes="GB2312" end if WScript.echo file,Usage,Codes slz.Close set slz = Nothing End Function
这个代码只检测了 BOM,把没有 BOM 的文件都认为是 GB2312 编码,很显然是错误的。并不是所有 UTF-8 编码的文件都带 BOM 标记的,事实上,绝大部分 UTF-8 文件都不带 BOM。
理论上,要准确地判断一个文件的编码是很困难的,但是判断 一个文件是否为 UTF-8 编码却相对比较简单,在《构建可扩展的Web站点》一书中就有很好的 PHP 代码:
<?php function is_valid_utf8(&$input){ $rx = '[\xC0-\xDF]([^\x80-\xBF]|$)'; $rx .= '|[\xE0-\xEF].{0,1}([^\x80-\xBF]|$)'; $rx .= '|[\xF0-\xF7].{0,2}([^\x80-\xBF]|$)'; $rx .= '|[\xF8-\xFB].{0,3}([^\x80-\xBF]|$)'; $rx .= '|[\xFC-\xFD].{0,4}([^\x80-\xBF]|$)'; $rx .= '|[\xFE-\xFE].{0,5}([^\x80-\xBF]|$)'; $rx .= '|[\x00-\x7F][\x80-\xBF]'; $rx .= '|[\xC0-\xDF].[\x80-\xBF]'; $rx .= '|[\xE0-\xEF]..[\x80-\xBF]'; $rx .= '|[\xF0-\xF7]...[\x80-\xBF]'; $rx .= '|[\xF8-\xFB]....[\x80-\xBF]'; $rx .= '|[\xFC-\xFD].....[\x80-\xBF]'; $rx .= '|[\xFE-\xFE]......[\x80-\xBF]'; $rx .= '|^[\x80-\xBF]'; return preg_match("!$rx!", $input) ? 0 : 1; } ?>
我们要做的就是改写成 VBS:
Function read(path) '将Byte()数组转成String字符串 Dim ado, a(), i, n Set ado = CreateObject("ADODB.Stream") ado.Type = 1 : ado.Open ado.LoadFromFile path n = ado.Size - 1 ReDim a(n) For i = 0 To n a(i) = ChrW(AscB(ado.Read(1))) Next read = Join(a, "") End Function 'Author: Demon 'Date: 2011/11/10 'Website: http://demon.tw Function is_valid_utf8(ByRef input) 'ByRef以提高效率 Dim s, re Set re = New Regexp s = "[\xC0-\xDF]([^\x80-\xBF]|$)" s = s & "|[\xE0-\xEF].{0,1}([^\x80-\xBF]|$)" s = s & "|[\xF0-\xF7].{0,2}([^\x80-\xBF]|$)" s = s & "|[\xF8-\xFB].{0,3}([^\x80-\xBF]|$)" s = s & "|[\xFC-\xFD].{0,4}([^\x80-\xBF]|$)" s = s & "|[\xFE-\xFE].{0,5}([^\x80-\xBF]|$)" s = s & "|[\x00-\x7F][\x80-\xBF]" s = s & "|[\xC0-\xDF].[\x80-\xBF]" s = s & "|[\xE0-\xEF]..[\x80-\xBF]" s = s & "|[\xF0-\xF7]...[\x80-\xBF]" s = s & "|[\xF8-\xFB]....[\x80-\xBF]" s = s & "|[\xFC-\xFD].....[\x80-\xBF]" s = s & "|[\xFE-\xFE]......[\x80-\xBF]" s = s & "|^[\x80-\xBF]" re.Pattern = s is_valid_utf8 = (Not re.Test(input)) End Function s = read("utf-8.txt") '读取文件 WScript.Echo is_valid_utf8(s) '判断是否UTF-8+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
yu2n说道:[code] ' 检察文件是否为UTF-8,有BOM/无BOM皆可,读取文件BOM头/前4Kbit判读 Function is_valid_utf8(ByVal file) is_valid_utf8 = False '将Byte()数组转成String字符串 Dim ado, a(), i, n, Bin, s, re Set ado = CreateObject("ADODB.Stream") ado.Type = 1 : ado.Open ado.LoadFromFile file n = ado.Size - 1 ' 检查空文件/限制读取4Kbit If n = 1024*4-1 Then n = 1024*4-1 '4Kbit ' 使用BOM判断 Bin = ado.read(2) If AscB(MidB(Bin,1,1)) = &HEF And AscB(MidB(Bin,2,1)) = &HBB Then is_valid_utf8 = True : Exit Function End If '将Byte()数组转成String字符串 ReDim a(n) : ado.Position = 0 For i = 0 To n a(i) = ChrW(AscB(ado.Read(1))) Next '使用正则表达式判断 Set re = New Regexp s = "[\xC0-\xDF]([^\x80-\xBF]|$)" s = s & "|[\xE0-\xEF].{0,1}([^\x80-\xBF]|$)" s = s & "|[\xF0-\xF7].{0,2}([^\x80-\xBF]|$)" s = s & "|[\xF8-\xFB].{0,3}([^\x80-\xBF]|$)" s = s & "|[\xFC-\xFD].{0,4}([^\x80-\xBF]|$)" s = s & "|[\xFE-\xFE].{0,5}([^\x80-\xBF]|$)" s = s & "|[\x00-\x7F][\x80-\xBF]" s = s & "|[\xC0-\xDF].[\x80-\xBF]" s = s & "|[\xE0-\xEF]..[\x80-\xBF]" s = s & "|[\xF0-\xF7]...[\x80-\xBF]" s = s & "|[\xF8-\xFB]....[\x80-\xBF]" s = s & "|[\xFC-\xFD].....[\x80-\xBF]" s = s & "|[\xFE-\xFE]......[\x80-\xBF]" s = s & "|^[\x80-\xBF]" re.Pattern = s is_valid_utf8 = (Not re.Test(Join(a, ""))) End Function [/code]