无效的 UTF-8 字节序列 Ruby

4
我有一个字符串如下 "abce\xC3".sub("a","A"),当我执行这行代码时,会出现以下错误。
ArgumentError: invalid byte sequence in UTF-8
    from (irb):20:in `sub'
    from (irb):20
    from /home/vijay/.rvm/rubies/ruby-2.0.0-p598/bin/irb:12:in `<main>'

有人能帮我解决这个问题吗?


3
"\xC3" 这个字节不是一个有效的 UTF-8 字符。当你从源头获取这个值(或者你对 Ruby 字符串操作的假设)时,就会出现问题。为了获得帮助,你需要解释一下这个值应该表示什么,或者它是如何被读入你的程序中的。 - Neil Slater
2
\xC3 是从哪里来的?在 UTF-8 中,它表示必须跟随第二个字节(就像 ä\xA4 一样)。 - cremno
"ITZVÃ" 这是我正在处理的确切字符串。 - Vijay
似乎Ruby 2.2不会引发错误,即sub可以处理/跳过无效的字节序列。 - Stefan
"ITZVÃ" 是文件的内容。当我读取这个文件时,z = File.open("x"); z.read(5); 输出应该是 ITZV\xC3\x83,但实际上我得到的是 ITZV\xC3。@Stefan 你有关于为什么在 Ruby 中会发生这种情况的任何想法吗? - Vijay
@Vijay请看下面的答案 - Stefan
3个回答

8

正如Arie已经回答的那样,这个错误是因为无效的字节序列\xC3

如果您使用的是Ruby 2.1+,您还可以使用String#scrub来将无效字节替换为给定的替换字符。这里:

a = "abce\xC3"
# => "abce\xC3" 
a.scrub
# => "abce�"
a.scrub.sub("a","A")
# => "Abce�"

5

您需要确定希望将 \xC3 转换成什么。它代表字符 Ã 吗?

您看到此错误是因为在(默认的)UTF-8编码中,\xC3 不是有效的字节序列。您可以先更正字符串的编码(通过回答上面的问题),然后再进行替换。

"abce\xC3".force_encoding("iso-8859-1").sub('a', 'A')

如果编码不重要,比如你处理的是字节序列而不是字符序列,那么你可以强制使用 ASCII-8BIT 编码。

"abce\xC3".force_encoding("ASCII-8BIT").sub('a', 'A')

你是如何发现 \xC3 是代表的是 Ã 的? - Vijay
2
要将字符串转换为UTF-8,请使用"abce\xC3".force_encoding('iso-8859-1').encode('utf-8'),或者更好的方法是在读取字符串时设置正确的编码。 - Stefan
@Vijay 它是一个单字节,超出了正常ASCII编码的范围,所以我尝试了8位编码。 - Arie Xiao

2

关于您的评论 / 实际问题:

"ITZVÃ" is content of file. When i read the file.

 z = File.open("x")
 z.read(5)

Then output should be ITZV\xC3\x83 instead i am getting ITZV\xC3

这是因为在UTF-8中,Ã是一个多字节字符,也就是说您的字符串有5个字符,但是有6个字节:

"ITZVÃ".chars #=> ["I", "T", "Z", "V", "Ã"]
"ITZVÃ".bytes #=> [ 73,  84,  90,  86, 195, 131]

z.read(5) 从文件中读取了5个字节,因此返回了一个不完整的UTF-8字符串:

require 'tempfile'

z = Tempfile.new('foo')
z << 'ITZVÃ'

z.rewind
z.read(5) #=> "ITZV\xC3"

您需要读取6个字节:

z.rewind
z.read(6) #=> "ITZV\xC3\x83"

请注意,read 总是返回 ASCII-8BIT 编码的字符串。您需要手动设置不同的编码:
z.rewind
z.read(6).force_encoding('utf-8') #=> "ITZVÃ"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接