问题描述
我有一个Ruby CGI(不是Rails),可以从Web表单中挑选照片和标题。我的用户非常热衷于使用智能引号和连字,他们是从其他来源粘贴的。我的Web应用程序不能很好地处理这些非ASCII字符,是否有快速的Ruby字符串操作例程可以清除非ASCII字符?
推荐答案
使用字符串#encode
从Ruby 1.9开始,在字符串编码之间进行转换的官方方式是使用String#encode。
要简单地删除非ASCII字符,您可以执行以下操作:
some_ascii = "abc"
some_unicode = "áëëçüñżλφθΩ"
more_ascii = "123ABC"
invalid_byte = "255"
non_ascii_string = [some_ascii, some_unicode, more_ascii, invalid_byte].join
# See String#encode documentation
encoding_options = {
:invalid => :replace, # Replace invalid byte sequences
:undef => :replace, # Replace anything not defined in ASCII
:replace => '', # Use a blank for those replacements
:universal_newline => true # Always break lines with
}
ascii = non_ascii_string.encode(Encoding.find('ASCII'), encoding_options)
puts ascii.inspect
# => "abce123ABC"
请注意,结果中的前5个字符是"abce1"-丢弃了"á",丢弃了一个"ë",但另一个"ë"似乎已转换为"e"。
原因是有时用Unicode表示相同的书写字符有多种方式。"á"是单个Unicode代码点。第一个"ë"也是。当Ruby在此转换过程中看到它们时,它会丢弃它们。但是第二个"ë"是两个代码点:一个普通的"e",就像您在ASCII字符串中看到的一样,后面跟着一个"组合变音符号"(this one),意思是"在前一个字符上加一个变音符号"。在Unicode字符串中,这些字符被解释为单个"字素"或可见字符。转换时,Ruby保留纯ASCII"e"并丢弃组合标记。
如果您决定要提供一些特定的替换值,可以这样做:
REPLACEMENTS = {
'á' => "a",
'ë' => 'e',
}
encoding_options = {
:invalid => :replace, # Replace invalid byte sequences
:replace => "", # Use a blank for those replacements
:universal_newline => true, # Always break lines with
# For any character that isn't defined in ASCII, run this
# code to find out how to replace it
:fallback => lambda { |char|
# If no replacement is specified, use an empty string
REPLACEMENTS.fetch(char, "")
},
}
ascii = non_ascii_string.encode(Encoding.find('ASCII'), encoding_options)
puts ascii.inspect
#=> "abcaee123ABC"
更新
有些人报告了与:universal_newline
选项有关的问题。我断断续续地看到过这种情况,但一直无法找到原因。
当它发生时,我看到Encoding::ConverterNotFoundError: code converter not found (universal_newline)
。但是,在一些RVM更新之后,我刚刚在以下Ruby版本下运行了上面的脚本,没有任何问题:
鉴于此,它似乎不是Ruby中的弃用特性,甚至不是bug。如果有人知道原因,请发表意见。