(我在here发布了类似的问题,但这个新问题不是重复的)。
我在这里开发的软件必须使用 Ruby 2.6.10 或 1.9.3 运行:
可重现的小问题:
b = "L\xF6sé侍"
我们这里有一个字符串,其中一个字节在 UTF-8 中是非法的(它是十六进制 F6 的字节)。从 Ruby 的角度来看,字符串的编码是
Encoding::UTF_8
。查看字节序列,我们可以看到
p b.bytes.to_a
=>
[76, 246, 115, 195, 169, 228, 190, 141]
我的目标是从字符串中删除 UTF-8 中非法的所有字节。我想在我的简单示例中获得一个内容为
"Lsé侍"
. 的字符串。
我试过了
c1 = b.encode('UTF-8', invalid: :replace, replace: '')
但是
c1
与b
具有相同的内容。然后我就尝试了
b.force_encoding(Encoding::ASCII_UTF8)
c2 = b.encode('UTF-8', invalid: :replace, replace: '')
但这也会删除字符 é 和 侍,因为它们在 ASCII 中无效。
我还考虑将 UTF8 中无效的字节值放在一起硬编码列表,然后简单地从字符串中删除它们,但这很丑陋。
有什么想法可以做到这一点吗?
更新:我根据我在
irb
中的实验发布了代码,但事实证明irb在这里的行为似乎与非交互式Ruby有点不同。您可以在here找到屏幕截图,该屏幕截图基于用户@mate给出的评论。为了使其工作,我无法在 JRuby 程序中分配该字符串(这在编译时已经被拒绝),而是从文件中读取它(无论如何,这就是我们“真实”应用程序中发生的情况)。
因此,如果您想重现该示例,请从此下载链接下载包含错误文本的文件,并使用以下 Ruby 脚本来运行它:
p RUBY_VERSION
str = File.read("./errf.txt")
p str.bytes.to_a
str2 = str.encode('UTF-8', invalid: :replace, replace: '')
p str2.bytes.to_a
您可以使用
each_char
拆分字符串,使用 valid_encoding?
选择有效字符,然后重新组合剩余的字符:
b = "L\xF6sé侍"
p b
p b.each_char.select(&:valid_encoding?).join()
输出:
"L\xF6sé侍"
"Lsé侍"