Character encoding 使用Rebol 3执行文件编码转换
我想使用REBOL3读取拉丁文1中的文件并将其转换为UTF-8。是否有我可以使用的内置函数,或一些外部库?我在哪里可以找到它?现在没有内置的,对不起。下面是一个简单的拉丁语-1到UTF-8转换的实现,这是我不久前编写并与Rebol 3一起使用的:Character encoding 使用Rebol 3执行文件编码转换,character-encoding,rebol,file-conversion,rebol3,Character Encoding,Rebol,File Conversion,Rebol3,我想使用REBOL3读取拉丁文1中的文件并将其转换为UTF-8。是否有我可以使用的内置函数,或一些外部库?我在哪里可以找到它?现在没有内置的,对不起。下面是一个简单的拉丁语-1到UTF-8转换的实现,这是我不久前编写并与Rebol 3一起使用的: latin1-to-utf8: func [ "Transcodes a Latin-1 encoded string to UTF-8" bin [binary!] "Bytes of Latin-1 data" ] [ to
latin1-to-utf8: func [
"Transcodes a Latin-1 encoded string to UTF-8"
bin [binary!] "Bytes of Latin-1 data"
] [
to-binary collect [foreach b bin [keep to-char b]]
]
注意:此代码针对易读性进行了优化,而不是以任何方式进行性能优化。(从性能角度来看,这完全是愚蠢的。你已经被警告过了。)
更新:合并了@BrianH的简洁的“拉丁-1字节值对应于Unicode码点”优化,这使得上面的内容压缩为一行(同时稍微不那么愚蠢)。还是。有关内存使用的更优化版本,请参阅@BrianH的漂亮答案。这里有一个版本应该更快一些,至少使用更少的内存
latin1-to-utf8: func [
"Transcodes a Latin-1 encoded string to UTF-8"
bin [binary!] "Bytes of Latin-1 data"
] [
to binary! head collect/into [
foreach b bin [
keep to char! b
]
] make string! length? bin
]
它利用了与相应的Unicode代码点具有相同数值的拉丁-1字符。如果要从另一个字符集进行转换,但情况并非如此,则可以在b
上进行计算以重新映射字符
由于各种原因,它使用的内存更少,速度更快:
- 通常,
创建块。我们使用collect
并将字符串作为目标传递给它。字符串使用的内存少于整数或字符块collect/into
- 我们将字符串预先分配到输入数据的长度,这样可以节省重新分配的时间
- 我们让Rebol的本机代码转换字符,而不是自己计算
- 循环中的代码更少,因此它应该运行得更快
如果需要将其设置为UTF-8的原因是需要在Rebol中将文件作为字符串处理,只需将
跳过为二进制
并按原样返回字符串。或者您可以只处理二进制源数据,只需使用将二进制中的字节转换为char函数,它为不属于有效utf-8序列的字节搜索二进制值。我们可以循环,直到找到并替换了所有这些值,然后将二进制值转换为字符串:
latin1-to-utf8: func [
"Transcodes bin as a Latin-1 encoded string to UTF-8"
bin [binary!] "Bytes of Latin-1 data"
/local t
] [
t: make string! length? bin
foreach b bin [append t to char! b ]
t
]
latin1-to-utf8: function [binary [binary!]][
mark: :binary
while [mark: invalid-utf? mark][
change/part mark to char! mark/1 1
]
to string! binary
]
此函数用于修改原始二进制文件。我们可以创建一个新字符串,使二进制值保持不变:
latin1-to-utf8: function [binary [binary!]][
mark: :binary
to string! rejoin collect [
while [mark: invalid-utf? binary][
keep copy/part binary mark ; keeps the portion up to the bad byte
keep to char! mark/1 ; converts the bad byte to good bytes
binary: next mark ; set the series beyond the bad byte
]
keep binary ; keep whatever is remaining
]
]
奖励:这里是上面的一个wee版本-rebmu/args snippet#{DECAFBAD}
其中snippet
是:
; modifying
IUgetLOAD"invalid-utf?"MaWT[MiuM][MisMtcTKm]tsA
; copying
IUgetLOAD"invalid-utf?"MaTSrjCT[wt[MiuA][kp copy/partAmKPtcFm AnxM]kpA]
@giuliolunati注意到,to binary数据是一个小包装器,它覆盖了我认为更好的表达式:to binary!数据。通过使用TO直接转换为数据类型,您可以编写类似于(条件[string!][binary!])数据的内容。为什么有些人认为他们一直用来指定类型的感叹号太刺耳,需要一个包装器,我不明白,但有些人确实这么认为。但是,如果您对某些东西是否内置感到好奇,您可以使用源代码,例如,从源代码到二进制代码,并查看它是否调用并且不是本机的!或者行动!旁注:我认为在这个时代,将输入文件本身转换为UTF-8是最好的主意……如果您的情况允许的话。使用下面的@earl方法很容易做到这一点,然后将其写出来。例如,写%myfile.utf8(拉丁文1-to-utf8读%myfile.latin1),那么你就不必关心转换的速度有多慢,因为你只做了一次…完全同意你的看法。我的所有文件都是utf8:-)但其他一些则不是:-(非常整洁,+1!特别是用于记住拉丁语1到代码点的对应关系。也是(capped)实用性的一个很好的例子)整数!值作为二进制的元素。发现“append”比collect/into快2倍。请参阅我的答案。与其他建议的变体不同,此版本不返回二进制!
,而是返回字符串!
(从技术上讲,它只将拉丁语1解码为内存中的Unicode,但不会将其再次编码为UTF-8)。要解决此问题,您必须将最后一行更改为“二进制”!t
。与其他建议的变体不同,此版本不返回“二进制”,而是返回一个字符串!
(因此,从技术上讲,它只将拉丁语1解码为Unicode,但不会将其再次编码为UTF-8)。因此,对于真正的拉丁语-1到UTF-8转码,只需省去到字符串的调用。
比其他调用快得多:修改版本9x,复制版本13x。太好了@rgchris!@earl我想我没有注意。正如你所说,在这两种情况下,删除到字符串!
并返回二进制代码都很容易。谢谢链接:)