|
|
导航: |
论坛 -> DELPHI技术
斑竹:liumazi,sephil |
|
作者: |
yookee (yookee) |
★☆☆☆☆ |
-
|
盒子活跃会员 |
|
2024/3/10 20:41:54 |
标题: |
读取文本时,多字节编码被截断时如何处理 |
浏览:806 |
|
加入我的收藏 |
楼主: |
Windows下的默认编码是Ansi,处理多字节编码如果遇到一个字符被截断,如三字节的Unicode或双字节的GB2312/GB18030只读了一个字节,这种情况正规的处理方式是什么。
问题源自:我用QDAC里的QXML读GB2312编码的文件,有的源文件因为生成时的字段长度有限制,且中英文混杂,有时可能某文本域的最后一个字符被直接截断,只写了一个字节,读到这里时会报错。一般文本编辑器打开这类文件也会报错,而且显示的是一个怪字符。 经常一次性读取几百兆大小的XML文件,偶尔碰到这个问题弹窗时挺崩溃的。我又没办法要求源文件加大字段长度限制。
大家在日常工作中一般是怎么处理的。
----------------------------------------------
- |
作者: |
|
2024/3/10 22:01:34 |
1楼: |
XML有标头。。 不规范的 总要识别的。 不识别就处理绝对截断啊
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/>http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
|
作者: |
|
2024/3/10 22:25:51 |
2楼: |
xml是一种标准, 不是正则表达式, 为什么会有长度这种说法?
----------------------------------------------
delphi界写python最强, python界写delphi最强. 写自己的代码, 让别人去运行.
|
作者: |
yookee (yookee) |
★☆☆☆☆ |
-
|
盒子活跃会员 |
|
2024/3/10 22:40:09 |
3楼: |
可能没描述清楚
比如<name>namestring</name> namestring是一个最长50Byte的GB2312字符串,因为有英文等单字节字符,一个超过50Byte的字符串写入时,可能到第49Byte的时候刚好写完一个字符,下一个是双字节的字符,因为XML生成源的问题(多个厂家的不规范写入,我无法控制),第50个字节直接写了双字节字符的第一个字节。
几百万行的XML,一次处理好几个,只是偶尔有一个文件的某行出现这种情况,如果为了避免这种情况,每行都去识别截断,效率太低了。
----------------------------------------------
-
|
作者: |
|
2024/3/11 8:48:47 |
4楼: |
<name></name>之间的不就是完整的字串吗?
----------------------------------------------
链接:https://pan.baidu.com/s/12jzmECYKhGCsHBxz8tmB6w 提取码:pelr --来自百度网盘超级会员V9的分享
|
作者: |
|
2024/3/11 9:06:13 |
5楼: |
所有文本进内存二话不说全部转成unicode再处理
----------------------------------------------
-
|
作者: |
yookee (yookee) |
★☆☆☆☆ |
-
|
盒子活跃会员 |
|
2024/3/11 9:07:41 |
5楼: |
我又看了一下源文件,出错的地方还是我描述错了 因为GB2312对ASCII码(0-127)之后的字符都采用两个字节表示,高位字节和低位字节都大于0x7F
如果读取的是一个大于0x7F的字节,会接着读取后一个字节作为一个字符,如果这个字符出现在字符串中间,无非解析出来就是一个怪异的字符
出错的地方刚好是namestring最后一个字节,解析时就连带把</name>的<作为第二个字节吞了
----------------------------------------------
-
|
作者: |
|
2024/3/11 9:18:18 |
6楼: |
这种情况,你可以在GB2312编码的情况下, 用字符串替换,将所有的'</'子串,替换为#13'</'子串
若想更保险,可以用正则将'(\</\w+\>)'替换为'\n\1'
----------------------------------------------
-
|
作者: |
yookee (yookee) |
★☆☆☆☆ |
-
|
盒子活跃会员 |
|
2024/3/11 9:40:03 |
6楼: |
XMLSpy能正确识别,文本编辑器会老老实实按多字节去显示
此帖子包含附件:
大小:81.0K |
----------------------------------------------
-
|
作者: |
|
2024/3/11 9:53:12 |
7楼: |
用WideString类型可以处理中文字符。
----------------------------------------------
-
|
作者: |
|
2024/3/11 18:20:47 |
8楼: |
gb2312包括后续扩展的gbk其实都可以直接当作ansi处理的,如果出乱码就说明你这个编码不对。至于你说的截断,应该是全角字符占2BYTE,但是你计算长度的时候没有区别导致从中间截断而出现乱码吧? 先转成utf8或者utf16也就是widestring,然后就不会有这种问题了。
----------------------------------------------
--
|
作者: |
yookee (yookee) |
★☆☆☆☆ |
-
|
盒子活跃会员 |
|
2024/3/11 19:10:04 |
9楼: |
源生文件就是GB18030的,只是我看基本都用的双字节GB2312部分。 300MB+的XML文件,而且是多个,几乎每天都会更新,转utf8太费事了。
----------------------------------------------
-
|
作者: |
|
2024/3/11 21:36:38 |
10楼: |
以下是读取文件的代码 ms:TMemoryStream; stlist:TStringList ;
ms:=TMemoryStream.Create; ms.LoadFromFile(filename); //读取Unicode编码 ms.Seek(2,soFromBeginning); stlist.LoadFromStream(ms,TEncoding.Unicode); stlist.Text中就是文字了
----------------------------------------------
-
|
作者: |
|
2024/3/11 23:45:42 |
11楼: |
GB18030和GB2312是不一样的哟,你可以把这个GB18030看作国产的UTF8,具体资料可以去查一下。 windows系统可以直接用multibytetowidechar函数转换,参数指定18030编码就是了。 linux则可以根据local函数配套转换,也就是setlocal(...)配合mbstowcs函数, delphi里应该也会有对应的函数,查一下就没问题了。
----------------------------------------------
--
|
作者: |
|
2024/3/12 10:37:12 |
12楼: |
GB18030是GBK的超集,GBK是GB2312的超集,它们三者是向下兼容的 GB18030对比GBK多出了4字节编码的字符,所以GB18030可以表达完整的Unicode字符集
----------------------------------------------
-
|
作者: |
yookee (yookee) |
★☆☆☆☆ |
-
|
盒子活跃会员 |
|
2024/3/12 10:37:17 |
12楼: |
GB18030的双字节部分就是GB2312
我想了一下,按编码去从头开始逐字节解码的思路行不通,因为源文件在写文件时就没有严格按照编码来,这也就是为什么文本编辑器都无法“正确理解”文件,而XMLSpy是按照不完全匹配去解析的,也就是要先向后读结束标签,所以能正确提示并显示,其实已经做了补全修正。
----------------------------------------------
-
|
作者: |
|
2024/3/12 11:45:22 |
13楼: |
不知道你们在讨论啥……这种情况下,就别用现成的XML解析类来做了呗。先把 XML 文本当作 ansi 即可,自己解析出字符串,再尝试用UTF8或者ANSI或者其他来转换即可。哪一种类型转换不出错就是哪一种喽
----------------------------------------------
-
|
作者: |
|
2024/3/12 14:37:13 |
14楼: |
有一个函数,ByteType(),用于判断字符串中的某个字节是单字节字符,双字节字符的第一个字节,还是双字节字符的第二个字节。 除了这个函数,SysUtils单元里面还有其它的一些处理字符函数,可以去看看
https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.SysUtils.ByteType
----------------------------------------------
Delphi MlSkin 它能让你的程序拥有像QQ一样多彩炫丽的外观http://www.pngui.com;http://www.xeframework.com
|
|