AnsiPos,ByteType,AnsiStrScan 等函数对非当前代码页不支持 ( 积分: 200 )

  • 主题发起人 主题发起人 xuechao
  • 开始时间 开始时间
X

xuechao

Unregistered / Unconfirmed
GUEST, unregistred user!
AnsiPos,ByteType,AnsiStrScan,StringReplace 等函数只支持当前代码页,对非当前代码页不支持,除了转换为Unicode再处理,还有其他方法吗?
例如我要在 简体代码页936(GBK) 处理 繁体代码页950(Big5)的字符串,用这些函数就可能有问题,反之亦然。
因为 LeadBytes variable 在不同的代码页中是不同的。
 
AnsiPos,ByteType,AnsiStrScan,StringReplace 等函数只支持当前代码页,对非当前代码页不支持,除了转换为Unicode再处理,还有其他方法吗?
例如我要在 简体代码页936(GBK) 处理 繁体代码页950(Big5)的字符串,用这些函数就可能有问题,反之亦然。
因为 LeadBytes variable 在不同的代码页中是不同的。
 
请问什么是“非当前代码页”?
 
听得有点糊涂,当前代码页是什么意思
 
假设 Windows2000 中的 区域设置中的语言的默认值为 繁体中文(Big5码)
系统要处理简体中文的字符串,传入的两个字符串为 GBK 码,不是Big5码
AnsiPos('简体','简体中文')
ByteType('简体中文ddsa',7)
 
Windows 2000 英文版 中使用
AnsiPos('卫','何丽')
 
你用widestring, widechar系列的类型就没有问题了
 
楼主认为AnsiPos、ByteType 等函数在不同语系的Windows 中处理相同的数据时可能会出问题,但你举的几个例子并不能支持这种说法。因为,AnsiPos('简体','简体中文')和ByteType('简体中文ddsa',7)这两条语句不管是在简体还是繁体中文的Windows 里面执行的结果都是一样的。
就我个人对ANSI字符集和代码页等问题的认识而言,这是再自然不过的事情。实际上,对任何一个ANSI(也即非Unicode)的应用程序来说,根本不存在所谓的“非当前代码页字符串”,在程序里面的任何一个字符串都会被当作系统当前默认语系的字符串来处理。就拿楼主所举的字符串例子来说吧,当我们在源程序中写下“AnsiPos('简体','简体中文')”这条语句时(假设我们是在简体中文环境下开发程序),由于AnsiPos函数是处理ANSI字符串的,而ANSI字符串又是基于系统当前默认语系的字符集的,所以这条语句在编译时编会被编译为类似于“AnsiPos(#$BC#$F2#$CC#$E5,#$BC#$F2#$CC#$E5#$D6#$D0#$CE#$C4)”这样的代码(其中的十六机制数就是“简体”和“简体中文”几个汉字在GBK字符集中的编码值)。当程序运行在简体中文的系统上的时候,这些编码值所代表的就是“简体”和“简体中文”这两个字符串。但把这个程序放到繁体中文的系统上运行的时候,它会用繁体中文语系的Big5字符集来解释这些编码值(注意,此时从已编译的程序的角度而言,它所处理的字符串--实际上是一连串的编码值组成的序列--并没有变,变的是不同语系的字符集对这些编码的定义),我们可以做一个小小的试验:用记事本写一个包含“简体中文”这几个字的文本文件,然后用IE来打开它。如果IE的编码为“简体中文”的话,那么毫无疑问文档内容会显示出“简体中文”这几个字;但如果我们将IE的编码改为“繁体中文”,你就会看到文档已经被显示成了“潠极笢恅”这几个字(注意了,这几个可不是什么乱码,而是在GBK和Big5字符集中都确确实实存在的合法的汉字字符)。这个试验表明:“简体中文”这几个字在GBK中的编码如果放到Big5里面去的话,表示的是“潠极笢恅”这四个字。所以我们在简体中文系统下开发的程序在简体中文系统下执行“AnsiPos(#$BC#$F2#$CC#$E5,#$BC#$F2#$CC#$E5#$D6#$D0#$CE#$C4)”这条语句时,可以认为它执行的就是我们在源程序里所写的“AnsiPos('简体','简体中文')”这条语句;但如果是在繁体中文系统下执行的话,这条语句就会被解释成“AnsiPos('潠极','潠极笢恅')”了。虽然两者从自然语言文字的角度来说完全不同,但从计算机程序的角度而言,它们都是由一连串相同的编码组成的序列。所以不论是在简体还是繁体中文系统中,这条语句的执行结果都是一样的。因此,对于ANSI程序来说,并不存在什么“非当前代码页的字符串”,所有的字符串都会被(事实上也只能)当作系统当前默认代码页的字符串来处理--举个可能不是很恰当的例子吧--这就跟电影里面黄飞鸿把“I Love You”说成(并且也理解成)“爱老虎油”是一样的道理。
至于英文版的操作系统有点特殊,因为Delphi 里面所有带Ansi-前缀的函数几乎都会直接或者间接地调用到ByteType函数,而这个函数首先会判断系统当前默认的语系是否远东语系,如果不是,它就会直接判断为单字节字符。所以如果要在非远东语系的Windows 系统中处理包含远东字符的字符串的话,最好还是不要用带Ansi-前缀的函数,而是用普通的字符串处理函数,将所有的字符串(不管它包含什么字符)都当作是由一个个字节而不是字符组成的序列来处理。比如,将AnsiPos('卫','何丽')改成Pos('卫','何丽'),这样就不会有问题了。
 
to: chenybin
我提问时有说除了转换为Unicode再处理,有没有其他方法。

to: SparkV
我举的例子在两个系统是没有问题。但其他情况有可能产生错误的结果,不是所有的情况都是对的。我现在的要做的是:在 繁体(BIG5)中读取 简体(GBK) 字符串进行处理,或者反之。

LeadBytes variable 在这两个字符集中不同,导致 ByteType 函数在不同的字符集产生不同的结果。

GBK范围:
第一字节: 0x81 - 0xFE, 第二个字节 0x40 - 0x7E, 0x80 - 0xFE
BIG5:
第一字节: 0xA1 - 0xF9 , 第二字节:0x40 - 0x7E, 0xA1 - 0xFE

我的想法是写类似的函数,这些函数多一个代码页的参数。
 
to SparkV:
AnsiPos('卫','何丽') 在英文版 返回 2, 但在简体中文版中 返回 0
 
楼主好像并没有理解我的意思,其实就是简单的一句话:当你在Delphi 程序中用string类型来处理字符串时,你只能老老实实地认为它里面的字符都是系统当前默认语系的字符集里面的字符。因此,所谓“在 繁体(BIG5)中读取 简体(GBK) 字符串”只是你一厢情愿的想法罢了--你拿什么证明或者说你的程序要怎样才能判断它读到的是Big5还是GBK编码的字符?要知道,无论是string类型还是文本文件,它们都是真正的“纯文本”,没有任何附加的格式可以表明它原来是用什么编码标准来保存的。

一个典型的例子:我在简体中文系统下用记事本写一个文本文件,然后以ANSI编码保存为文本文件。接下来把系统默认的语言切换为繁体中文,再用记事本打开那个文件,现在我看到程序中显示出来的内容肯定不是我原来写的那些东西。因为记事本根本不可能知道文件原来是用什么编码保存的,它只能按BIG5对编码的定义来解释它从文件中读到的每一个字节。相信当你写自己的程序的时候,也一样会碰到这样的困境。

你也许会说,如果我读的是带格式的文档像HTML或DOC等那不就可以知道文档的编码了吗?是的,这些格式化文档的确可以指出其中字符的编码类型。但如果你因此就认为你可以不加处理地将这些字符读进你的程序的话,那就错了。要知道,你的程序是ANSI的,也就是说程序中是以ANSI的方式来处理字符串的。这样就会再次面对同样的困境:虽然你已经知道了读入的字符串的编码类型,但你没有以进行相应地处理而直接读入,由于原来的编码系统与现在的编码并不相同,所以还是错的,事实上你并没有得到文档原作者想要表达的字符。比如一个GBK编码的DOC文档里面保存了“简体中文”这几个字,现在你要把它读到你的程序里面(假设程序运行于繁体中文系统),如果你直接读入这几个字符,由于所谓字符实际上是用它的编码来表示的,所以你读到的其实是它们的编码。这样一来,你读到的字符编码虽然没有变,但由于源字符的编码方式与现在的不同,所以这些编码所表示的字符却变了--正如我在上面所说,GBK编码的“简体中文”进入BIG5环境中后就会被解释为“潠极笢恅”了。
因此,任何想要不加处理地读入一个字符串(不管你或你的程序是否知道字符串原来是用什么方式编码的)到ANSI程序中,而又希望能正确地保留原字符串的面貌(即字符串原作者所要表达的含义)的幻想都是徒劳的。你要做的就是根据你所知的关于要读入的字符串原来的编码方式的信息,相应地转换为BIG5编码的字符,才能在程序中进一步地来处理。
 
再致楼主--
如果是英文系统,可以用Pos来取代AnsiPos,这样到哪里都不会有问题。事实上,即使是在简体或繁体中文系统这样的多字节字符集环境,我个人的经验也是最好是用Pos。因为Pos是按组成字符串的每个字节的数据值来比较的,它不需要像AnsiPos那样多此一举地调用ByteType来判断字节的类型。再加上对于字符串查找这样的操作来说,得出结果的依据是被查找字符串的某一部分与待查找字符串完全地相同。所以无论是从效率还是适用范围的角度而言,Pos都比AnsiPos要更胜一筹。
 
SparkV:
我现在要做文件格式转换,从一种格式文件转换为另一种格式文件,转换过程中要进行字符串查找和替换,这两种格式文件都是GBK字符集,当然在GBK字符集下运行是没有问题的,但在BIG5 运行就可能有问题了。
 
easy,其实并没有你想的那么复杂。对于计算机来说,不管字符是怎么编码的,一旦它被保存到内存中,那就只是一连串(代表字符编码值)的字节数据而已。不管你在什么系统中读取这些字符串--简体也好,繁体也好,英文甚至是日文韩文德文希腊文……都好--字符串在内存中的表达方式即字节数据流都不会变。系统不会因为当前默认语系的字符集不支持某些编码而拒绝在字符串中存储它。比如,英文系统由于只需7位的ASCII编码即可保存所有基本的字符,所以编码值大于$7F的字符都是英文系统所不支持的。但这并不妨碍我们在程序中处理包含编码值大于$7F的字符--不支持仅仅意味着不能在界面中显示而已--当我们在英文系统中显示编码值大于$7F的字符时会看到一堆的小方块。但如果我们在程序中写下这样的程序时,S:=Chr($80),正如你所知道的--除非那个i超出了字符串S的长度范围,否则不管你在什么系统中执行它,都不会出问题。操作系统只会限制你往哪些内存写东西,但绝对不会管你往允许访问的内存中写什么东西。所以,存储在字符串中的字符是可以任意的,不管系统当前默认语言的字符集中是否有这个字符,只要你不把它显示出来,都不会有任何问题。
 
所以,你的问题很好解决。尽管在你的程序中读入要处理的字符串吧--别管字符串中都是些什么东西,也不用管程序运行在什么系统上--只要你查找的时候用的是与特定字符集无关的Pos这样的函数,就一定不会有问题。
 
举个例子
ansipos('|','億') 英文字符集 返回 2,GBK字符集 返回 0,Big5 字符集返回 2.
 
晕~不是说了吗?用Pos……
 
既然源格式和目的格式一样 就不要考虑什么编码了 都用ASCII考虑。。。
先用流一类的读入文件之后用文件的Seek进行查找和替换
速度不慢的。。。。
 
SparkV说的对。。。。用POS 全当成ASCII处理。。
不过还是当成文件直接用Seek比较快吧。。。
 
ansipos('|','億') 英文字符集 返回 2,GBK字符集 返回 0,Big5 字符集返回 2
ansipos('|','億') 正确的结果为0,但在英文版(英文字符集) 和 繁体版(Big5字符集)的结果为2,不正确。
我的方法:
1.转换为Unicode再处理,缺点为 Windows 9x 只支持少量的Unicode Win32 API函数。
2. 写AnsiPos,ByteType,AnsiStrScan类似的函数,这些函数多一个代码页的参数。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
后退
顶部