afan 发表于 2011-11-4 12:54:31

[已解决]如何判断字符串中含有ANSI编码不能保存的 Unicode 格式的字符

本帖最后由 afan 于 2011-11-5 10:09 编辑

先运行以下这个简单的脚本$str = BinaryToString('0x00A0', 3)
ClipPut($str)
Run('notepad.exe')
WinActivate('', '')
Sleep(100)
Send('^v')
Send('^s')在保存时会出现如下提示:
该文件含有 Unicode 格式的字符,当文件保存为 ANSI 编码的文本文件时,该字符将丢失。……
此时只能保存为U字头编码的文件才会不丢失字符。

如果需要判断编码的是“文件”,那可以使用 FileGetEncoding() 之类的简单判断。
但对于字符串,它不存在 BOM ,或者说是文件头信息,那又该如何判断呢?
尝试过用正则判断,但没找到相关的编码范围,只有放弃了。

请大家赐教,谢谢~

amxi 发表于 2011-11-4 14:21:38

有个StringisAscII函数
Checks if a string contains only ASCII characters in the range 0x00 - 0x7f (0 - 127).

$str = BinaryToString('0x00A0', 3)
       
        $result= StringIsASCII($str)
        if $result=1 then
                MsgBox(0,"",StringIsASCII($str))
       
ClipPut($str)
Run('notepad.exe')
WinActivate('', '')
Sleep(100)
Send('^v')
Send('^s')
       
Else
        $nes=BinaryToString('0x00A0',4 )
        ClipPut($nes)
Run('notepad.exe')
WinActivate('', '')
Sleep(100)
Send('^v')
Send('^s')
EndIf


提示是没有了,但貌似粘贴的一个空{:face (258):}

afan 发表于 2011-11-4 14:29:41

回复 2# amxi


    呵呵,这个只是检测字符串是否包含 0x00 到 0x7f (0-127)之间的 ASCII 字符,这个范围并不是ANSI编码的全部范围。比如一个双字节字符,不属于该检测范围,但是保存为ANSI编码是没有问题的。

感谢参与讨论~

amxi 发表于 2011-11-4 14:44:29

else下面这句
$nes=BinaryToString('0x00A0',3);4改回3. utf16
,虽然也提示:[]quote]
该文件含有 Unicode 格式的字符,当文件保存为 ANSI 编码的文本文件时,该字符将丢失。……
直接点确定的话没有让你选择编码,直接可以保存的.

ansiunicode哎,还不到那程度.

afan 发表于 2011-11-4 14:47:34

回复 4# amxi


    直接保存当然可以,不过已经丢失字符了。你将保存的文件重新打开就会发现,显示的是个问号~

afan 发表于 2011-11-4 14:54:17

之所以作此判断,是因为在将字符串保存为文件时可以使用 FileOpen() 选择编码模式。
虽然都直接用 Unicode 格式保存不会有问题,都如果是 ANSI 编码可以保存的还是尽量用ANSI编码,特别是保存的是诸如 .au3 的脚本文件。

amxi 发表于 2011-11-4 15:12:27

额,帮助文档里推荐脚本的编码是用utf8.

你这个编码问题太深了,潜不到了.

afan 发表于 2011-11-4 15:21:12

额,帮助文档里推荐脚本的编码是用utf8..
amxi 发表于 2011-11-4 15:12 http://www.autoitx.com/images/common/back.gif


    ANSI 或 UTF8 都好说,只要不保存为其它的Unicode UTF16 就好~

3mile 发表于 2011-11-4 18:10:25

#include <File.au3>
#include <winapi.au3>

$filename = "out.txt"
$CODE = _GetFileCode($filename)
MsgBox(0, 0, $CODE)

Func _GetFileCode($file)
        Local $nBytes
        $tBuffer = DllStructCreate("byte[" & 2 & "]")
        $hFile = _WinAPI_CreateFile($file, 2, 2)
        _WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer), 2, $nBytes)
        _WinAPI_CloseHandle($hFile)
        $sText = DllStructGetData($tBuffer, 1)
        Switch $sText
                Case "0xEFBB"
                        Return "UTF-8"
                Case "0XFEFF"
                        Return "Unicode big endian"
                Case "0XFEFE"
                        Return "Unicode"
                Case Else
                        Return "ANSI"
        EndSwitch
EndFunc   ;==>_GetFileCode

afan 发表于 2011-11-4 20:47:57

本帖最后由 afan 于 2011-11-4 20:52 编辑


3mile 发表于 2011-11-4 18:10 http://www.autoitx.com/images/common/back.gif


    3m 貌似没弄懂我的意思哦~ 我是说的检测还未成为“文件”的“字符串”~ 一楼说明了,如果是文件,内置函数 FileGetEncoding() 就可以检测。呵呵~

简单的说,判断以下字符串变量 $str 能否保存为 ANSI编码的文本,而不丢失字符~$str = BinaryToString('0x00A0', 3)

happytc 发表于 2011-11-4 21:24:36

回复 10# afan


    管它有没有,直接转换就可以了。实际应用中就是这样

#Include <WinAPI.au3>

$str = BinaryToString('0x00A0', 3)
$str = _WinAPI_WideCharToMultiByte($str, 65001)
MsgBox(0,0,$str)

afan 发表于 2011-11-4 21:37:52

回复afan


    管它有没有,直接转换就可以了。实际应用中就是这样
happytc 发表于 2011-11-4 21:24 http://www.autoitx.com/images/common/back.gif


    如果是不管它有没有就直接转换,如果1000个字符中只有1个需要转换那岂不是很不划算~ 而且也不知道转换得对否,貌似此例中的转换就是错误的。
转换还不如直接就用UTF8保存~

happytc 发表于 2011-11-4 22:20:48

如果是不管它有没有就直接转换,如果1000个字符中只有1个需要转换那岂不是很不划算~ 而且也不知道 ...
afan 发表于 2011-11-4 21:37 http://www.autoitx.com/images/common/back.gif

其实我想说的是,你这个命题本身就是个伪命题,没有 “字符串包含Unicode字符的说法”。不可能一个字符串包含Ansi和unicode两种编码,除非是自己写内存。

所以我才说,直接转。

估计你认为象:$Str = 'hello/你好/السلام عليكم'(分别是英语/中文/阿拉伯语的‘你好’)中的'hello'是ANSI的,别的是Unicode 的

afan 发表于 2011-11-4 22:28:28

其实我想说的是,你这个命题本身就是个伪命题,没有 “字符串包含Unicode字符的说法”。不可能一个字符 ...
happytc 发表于 2011-11-4 22:20 http://www.autoitx.com/images/common/back.gif


    看我三楼的回复,你还会提出我所指的“'hello'是ANSI的,别的是Unicode 的”这个问题吗?
判断中文,甚至分出简体、繁体、符号我都可以用正则轻松实现~

happytc 发表于 2011-11-4 23:08:15

本帖最后由 happytc 于 2011-11-4 23:23 编辑

回复 14# afan

所以问题就简化为:一个宽(unicode)字符串,若其中一个字符在 CodePage 制定的代码页中没有对应的表示时,怎么检测出来?
其实我上面说到的函数WideCharToMultiByte的参数中
int WideCharToMultiByte(
__in   UINT CodePage,
__in   DWORD dwFlags,
__in   LPCWSTR lpWideCharStr,
__in   int cchWideChar,
__outLPSTR lpMultiByteStr,
__in   int cbMultiByte,
__in   LPCSTR lpDefaultChar,
__outLPBOOL lpUsedDefaultChar
);
(http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130(v=vs.85).aspx)
在这函数中的后两个参数就是干这个活的:若一个字符在 CodePage 制定的代码页中没有对应的表示时,WideCharToMultiByte 就会使用后两个参数,也就是在遇到一个不能转换的字符时,函数便使用 pDefaultChar 参数指向的字符。如果这个参数指向为 NULL ,函数就会使用一个默认的字符。于是也就可以用这个特性检测出unicode字符串中不能转为ansi的字符

__outLPBOOL lpUsedDefaultChar // 宽字符字符串中,如果至少有一个字符不能转换为对应的多字节形式,函数就会把这个变量设为 TRUE 。如果所有字符都能成功转换,就会把这个变量设为 FALSE。 通常将此函数传入 NULL 值。
页: [1] 2 3
查看完整版本: [已解决]如何判断字符串中含有ANSI编码不能保存的 Unicode 格式的字符