标题: 用VBS判断无BOM头的文件是否UTF-8编码
作者: Demon
链接: https://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: https://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
微信赞赏支付宝赞赏
随机文章:
测试了一下,使用3个文本文件,一个无BOM的UTF8,一个有BOM的UTF8,一个ANSI,程序给出的结果都是-1,貌似有些问题。
文本中的文字是什么?
文本1是中英文混合,文本2和3都是纯英文。
具体内容。。。
文本1(Without BOM):
[宽带连接]
Encoding=1
Type=5
AutoLogon=0
UseRasCredentials=0
……
文本2(With BOM):
SWADSDA2
文本3(ANSI):
sfsdfsdf
————-兔年和龙年的分隔线————-
祝新年快乐!
这个结果有什么问题吗?
ANSI(GB2312)在ASCII范围内和UTF-8是兼容的,所以纯英文文本既可以认为是ANSI,也可以认为是UTF-8。
至于有BOM头的文件,这并不是该函数的功能。
多谢Demon,收益匪浅
顺便问下:
“至于有BOM头的文件,这并不是该函数的功能。”
后面判断utf-8的代码只能判断无BOM头的文件么?
是的,因为有BOM的很好判断,我就不写了。
你好,我用java写了下,并不能判断出来,你能不能把这段代码更为详尽的解释下,多谢了!
[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]
我对代码作了一些修改,,希望扩展一下功能,,但是发现对utf8的检测仍然不是很理想,,有时候会把含中文的gbk(ANSI)文件当成utf8,,把我测试的文件打包上传了,,希望大大们能帮我完善一下,,多谢!!
http://www.funp.net/796264
修改的代码现在看不到啊,能不能贴上来,谢谢啦