我想使用 Rebol 3 读取 Latin1 中的文件并将其转换为 UTF-8。是否有我可以使用的内置函数或一些外部库?我在哪里可以找到它?
4 回答
这是一个应该更快的版本,并且至少使用更少的内存。
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 代码点具有相同数值的 Latin-1 字符。如果您想从另一个不是这种情况的字符集进行转换,您可以对 进行计算b
以重新映射字符。
由于各种原因,它使用更少的内存并且速度更快:
- 通常,
collect
创建一个块。我们使用collect/into
并传递一个字符串作为目标。字符串比整数块或字符块使用更少的内存。 - 我们将字符串预分配到输入数据的长度,这样可以节省重新分配。
- 我们让 Rebol 的本机代码转换字符,而不是自己进行数学运算。
- 循环中的代码更少,因此它应该运行得更快。
这种方法仍然是一次将文件全部加载到内存中,并且仍然会生成一个中间值来存储结果,但至少中间值更小。也许这会让你处理更大的文件。
如果您需要它是 UTF-8 的原因是您需要在 Rebol 中将文件作为字符串处理,只需跳过to binary!
并按原样返回字符串。或者您可以只处理二进制源数据,只需使用to char!
每个字节转换二进制中的字节即可。
Rebol 有一个无效的 utf?用于搜索不属于有效 UTF-8 序列的字节的二进制值的函数。我们可以循环直到找到并替换所有这些,然后将我们的二进制值转换为字符串:
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
]
]
奖励:这是上面的Rebmu版本 - <code>rebmu/args 片段 #{DECAFBAD} 其中snippet
是:
; modifying
IUgetLOAD"invalid-utf?"MaWT[MiuM][MisMtcTKm]tsA
; copying
IUgetLOAD"invalid-utf?"MaTSrjCT[wt[MiuA][kp copy/partAmKPtcFm AnxM]kpA]
目前没有内置任何内容,抱歉。这是我不久前编写并与 Rebol 3 一起使用的 Latin-1 到 UTF-8 转换的简单实现:
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 的简洁的“Latin-1 字节值对应于 Unicode 代码点”优化,这使得上述内容崩溃为单行(同时稍微不那么愚蠢)。仍然。有关内存使用的更优化版本,请参阅@BrianH 的好答案。
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
]