Ответ 1
Использовать кодировку String #
Официальным способом преобразования между строковыми кодировками с 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 \n
}
ascii = non_ascii_string.encode(Encoding.find('ASCII'), encoding_options)
puts ascii.inspect
# => "abce123ABC"
Обратите внимание, что первые 5 символов в результате: "abce1" - "á" был отброшен, один "ë" был отброшен, а другой "ë", похоже, был преобразован в "e" .
Причиной этого является то, что иногда есть несколько способов выразить один и тот же написанный символ в Юникоде. "Á" является одним кодовым кодом 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"
Update
Некоторые из них сообщили о проблемах с опцией :universal_newline
. Я видел это с перерывами, но не смог отследить причину.
Когда это произойдет, я вижу Encoding::ConverterNotFoundError: code converter not found (universal_newline)
. Однако после некоторых обновлений RVM я просто запускал script выше в следующих версиях Ruby без проблем:
- рубин-1.9.2-P290
- рубин-1.9.3-P125
- рубин-1.9.3-Р194
- рубин-1.9.3-P362
- рубиново-2.0.0-preview2
- ruby-head (по состоянию на 12-31-2012)
Учитывая это, он не является устаревшей функцией или даже ошибкой в Ruby. Если кто-нибудь знает причину, прокомментируйте.