我正在从远程源读取数据,偶尔会在另一个编码中获取一些字符。它们并不重要。
我想得到一个“最佳猜测”utf-8字符串,并忽略无效数据。
主要目标是获取我可以使用的字符串,而不会遇到如下错误:
答案 0 :(得分:15)
我以为是这样的:
string.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?")
将用'?'取代所有知识。
忽略所有未知数,:replace => ''
:
string.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "")
修改强>
我不确定这是否可靠。我已经进入了偏执模式,一直在使用:
string.encode("UTF-8", ...).force_encoding('UTF-8')
脚本似乎正在运行,现在好了。但我很确定我早些时候会遇到错误。
编辑2:
即便如此,我仍然会出现间歇性的错误。不是每次,请注意。只是有时候。
答案 1 :(得分:3)
String #chars 或 String#each_char 。
# Table 3-8. Use of U+FFFD in UTF-8 Conversion
# http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf)
str = "\x61"+"\xF1\x80\x80"+"\xE1\x80"+"\xC2"
+"\x62"+"\x80"+"\x63"+"\x80"+"\xBF"+"\x64"
p [
'abcd' == str.chars.collect { |c| (c.valid_encoding?) ? c : '' }.join,
'abcd' == str.each_char.map { |c| (c.valid_encoding?) ? c : '' }.join
]
从Ruby 2.1开始,可以使用String#scrub 。
p [
'abcd' == str.scrub(''),
'abcd' == str.scrub{ |c| '' }
]
答案 2 :(得分:2)
这对我很有用:
"String".encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "").force_encoding('UTF-8')
答案 3 :(得分:2)
要忽略字符串中未正确UTF-8编码的所有未知部分,以下(如您最初发布的那样)几乎可以执行您想要的操作。
string.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "")
需要注意的是,如果认为字符串已经是UTF-8,则编码不会执行任何操作。因此,您需要更改编码,通过仍然可以编码UTF-8可以编码的全套unicode字符的编码。 (如果你不这样做,你会破坏任何不在那种编码中的字符 - 7位ASCII将是一个非常糟糕的选择!)所以请通过UTF-16:
string.encode('UTF-16', :invalid => :replace, :replace => '').encode('UTF-8')
答案 4 :(得分:0)
在@masakielastic的帮助下,我已经使用#chars方法为个人目的解决了这个问题。
诀窍是将每个角色分解为自己独立的块 ,以便ruby可以失败。
Ruby 需要在面对二进制代码等时失败。如果你不允许ruby继续前进并且在这个问题上遇到困难。所以我使用String #chars方法将给定的字符串分成一个字符数组。然后我将该代码传递给一个消毒方法,该方法允许代码在字符串中包含“微伪”(我的造币)。
因此,给定一个“脏”字符串,假设您在图片上使用了File#read
。 (我的情况)
dirty = File.open(filepath).read
clean_chars = dirty.chars.select do |c|
begin
num_or_letter?(c)
rescue ArgumentError
next
end
end
clean = clean_chars.join("")
def num_or_letter?(char)
if char =~ /[a-zA-Z0-9]/
true
elsif char =~ Regexp.union(" ", ".", "?", "-", "+", "/", ",", "(", ")")
true
end
end
允许代码在进程中的某个地方失败似乎是通过它的最佳方式。只要您在块中包含这些失败,您就可以获取仅接受UTF-8接受的ruby部分的可读性
答案 5 :(得分:0)
我没有幸运使用String #coding ala string.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "?")
的单行使用。不能为我可靠地工作。
但是我写了一个纯粹的红宝石“回填”String#scrub到MRI 1.9或2.0或任何其他没有提供String#scrub的红宝石。
https://github.com/jrochkind/scrub_rb
它使String#scrub在没有它的红宝石中可用;如果在MRI 2.1中加载,它将不执行任何操作,您仍将使用内置的String#scrub,因此它可以让您轻松编写可在任何这些平台上运行的代码。
它的实现有点类似于其他答案中提出的其他一些char-by-char解决方案,但它不使用流控制的异常(不要那样做),经过测试,并提供与之兼容的API MRI 2.1 String#scrub