如何摆脱红宝石中的非ascii字符

61 ruby unicode ascii cgi

我有一个Ruby CGI(不是rails),可以从Web表单中选择照片和标题.我的用户非常热衷于使用智能引号和连字,他们正在从其他来源粘贴.我的网络应用程序不能很好地处理这些非ASCII字符,是否有一个快速的Ruby字符串操作例程可以摆脱非ASCII字符?

Nat*_*ong 138

使用String #coding

从Ruby 1.9开始,在字符串编码之间进行转换的官方方法是使用String #coding.

要简单地删除非ASCII字符,您可以这样做:

some_ascii   = "abc"
some_unicode = "áëe?çüñ?????"
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 \n
}

ascii = non_ascii_string.encode(Encoding.find('ASCII'), encoding_options)
puts ascii.inspect
  # => "abce123ABC"
Run Code Online (Sandbox Code Playgroud)

请注意,结果中的前5个字符是"abce1" - 丢弃"á",丢弃一个"ë",但另一个"ë"似乎已转换为"e".

这样做的原因是有时有多种方法可以在Unicode中表达相同的书写字符."á"是单个Unicode代码点.第一个"ë"也是.当Ruby在转换期间看到这些时,它会丢弃它们.

但第二个"ë"是两个代码点:一个简单的"e",就像你在ASCII字符串中找到的那样,后面跟着一个"组合变音符号"(这个),这意味着"在前一个字符上加一个变音符号" ".在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 \n
  # 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"
Run Code Online (Sandbox Code Playgroud)

更新

有些人报告了该:universal_newline选项的问题.我间歇地看到了这一点,但未能找到原因.

当它发生时,我明白了Encoding::ConverterNotFoundError: code converter not found (universal_newline).但是,在一些RVM更新之后,我只是在以下Ruby版本下运行上面的脚本而没有问题:

  • 红宝石1.9.2-P290
  • 红宝石1.9.3-P125
  • 红宝石1.9.3-P194
  • 红宝石1.9.3-P362
  • 红宝石2.0.0 preview2
  • ruby-head(截至2012年3月12日)

鉴于此,它似乎不是一个已弃用的功能,甚至不是Ruby中的错误.如果有人知道原因,请评论.

  • 将符号`:universal_newline`更改为`:UNIVERSAL_NEWLINE_DECORATOR`可以解决我的问题. (7认同)
  • universal_newline选项在1.9.3-p194中被破坏 (2认同)

klo*_*ner 39


class String
 def remove_non_ascii(replacement="") 
   self.gsub(/[\u0080-\u00ff]/, replacement)
 end
end
Run Code Online (Sandbox Code Playgroud)

  • 在ruby 1.9中,我得到了"无效多字节转义"的例外.要修复它,而不是\ x80-\xff,我使用了\ u0080-\u00ff (23认同)

Sco*_*ott 20

这是我使用Iconv的建议.

class String
  def remove_non_ascii
    require 'iconv'
    Iconv.conv('ASCII//IGNORE', 'UTF8', self)
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 重要说明:这适用于1.8.7 (2认同)

Gre*_*egP 8

如果您有积极的支持,您可以使用I18n.transliterate

\n
I18n.transliterate("\xc3\xa1\xc3\xabe\xcc\x88\xc3\xa7\xc3\xbc\xc3\xb1\xc5\xbc\xce\xbb\xcf\x86\xce\xb8\xce\xa9")\n"aee?cunz?????"\n
Run Code Online (Sandbox Code Playgroud)\n

或者,如果您不想要问号......

\n
I18n.transliterate("\xc3\xa1\xc3\xabe\xcc\x88\xc3\xa7\xc3\xbc\xc3\xb1\xc5\xbc\xce\xbb\xcf\x86\xce\xb8\xce\xa9", replacement: "")\n"aeecunz"\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,这不会删除无效的字节序列,它只是替换非 ascii 字符。对于我的用例来说,这就是我想要的,而且很简单。

\n


Jos*_*man 0

Quick GS 揭示了这个讨论,提出了以下方法:

class String
  def remove_nonascii(replacement)
    n=self.split("")
    self.slice!(0..self.size)
    n.each { |b|
     if b[0].to_i< 33 || b[0].to_i>127 then
       self.concat(replacement)
     else
       self.concat(b)
     end
    }
    self.to_s
  end
end
Run Code Online (Sandbox Code Playgroud)