Ruby 1.9.x заменяет наборы символов определенными очищенными символами в строке.

Я ищу способ сделать следующий PHP-код в Ruby лаконичным и эффективным способом:

$normalizeChars = array('Š'=>'S', 'š'=>'s', 'Ð'=>'Dj','Ž'=>'Z', 'ž'=>'z', 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A',
        'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E', 'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I',
        'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U',
        'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss','à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a',
        'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i',
        'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u',
        'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b', 'ÿ'=>'y', 'ƒ'=>'f');
$cleanGenre = strtr($this->entryArray['genre'], $normalizeChars);

Здесь функция strtr() заменит символ слева на тот, что справа в массиве. Довольно удобно для уборки. Но я не могу найти ничего подобного в Ruby, то есть способа указать, какие символы заменять все в одном массиве, а не длинными условными выражениями для каждого символа.

Обратите внимание, что tr не будет работать, потому что вы не можете заменить одну букву двумя (D => Dj). Плюс это дает мне InvalidByteSequenceError: "\xC5" on US-ASCII для этой строки:

    entry["genre"].tr('ŠšŽž', 'SsZz')

Спасибо.


person kakubei    schedule 11.02.2013    source источник
comment
будет ли это работать: stackoverflow.com/a/7836947/166029?   -  person keymone    schedule 11.02.2013


Ответы (3)


Я облегчу вам реализацию

#encoding: UTF-8
t = 'ŠšÐŽžÀÁÂÃÄAÆAÇÈÉÊËÌÎÑNÒOÓOÔOÕOÖOØOUÚUUÜUÝYÞBßSàaáaâäaaæaçcèéêëìîðñòóôõöùûýýþÿƒ'
fallback = { 
  'Š'=>'S', 'š'=>'s', 'Ð'=>'Dj','Ž'=>'Z', 'ž'=>'z', 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A',
  'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E', 'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I',
  'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U',
  'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss','à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a',
  'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i',
  'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u',
  'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b', 'ÿ'=>'y', 'ƒ'=>'f'
  }

p t.encode('us-ascii', :fallback => fallback)
person peter    schedule 11.02.2013
comment
Спасибо Питер. У меня все еще есть эта ошибка в приложении, где оно не принимает ни один из этих символов, поэтому я не могу его проверить. Но я сделаю это, как только смогу понять, в чем проблема. - person kakubei; 12.02.2013
comment
может быть кодировкой из одного из ваших драгоценных камней, можете ли вы запустить фрагмент кода, который я предоставил сам по себе? Также не забудьте сохранить сам скрипт в UTF-8. - person peter; 12.02.2013
comment
Питер, огромное спасибо, это помогло, и вы были достаточно любезны, чтобы найти время, чтобы написать все необходимые символы. Вы поднялись выше запредельного, и я очень ценю это. Спасибо! - person kakubei; 12.02.2013

В Ruby 1.9.3 вы можете использовать опцию :fallback с encode:

"ŠšŽžÐ".encode('us-ascii', :fallback => { [your character table here] })
=> "SsZzDj"

Это также возможно сделать с помощью gsub, так как он принимает таблицу преобразования в качестве хеш-аргумента в 1.9.x:

"ŠšŽžÐ".gsub(/[ŠšŽžÐ]/, [your character table here])
=> "SsZzDj"

Или еще лучше (от @steenslag):

character_table = [your table here]
regexp_keys     = Regexp.union(character_table.keys) 
"ŠšŽžÐ".gsub(regexp_keys, character_table)
=> "SsZzDj"

Такое преобразование символов называется транслитерацией, и это полезно знать, если вы хотите узнать больше в Google. решения (есть много библиотек Ruby, поддерживающих транслитерацию, но ни одна из протестированных мной не поддерживала ваш набор символов полностью).

person Casper    schedule 11.02.2013
comment
Каспер, спасибо, попробую. У меня проблема в том, что я не могу ничего проверить в консоли со специальными символами, вставка вашего примера gsub дает мне эту ужасную вещь: "\U+FFC5\U+FFA0\U+FFC5\U+FFA1\U+FFC5\U+FFBD\U+FFC5\U+FFBE\U+FFC3".gsub(/[\U+FFC5\U+FFA0\U+FFC5\U+FFA1\U+FFC5\U+FFBD\U+FFC5\U+FFBE\U+FFC3]/, ['SsZzDj']). Добавление его в код дает мне ошибку InvalidByteSequenceError: "\xC5" on US-ASCI. Я действительно не знаю, почему. - person kakubei; 11.02.2013
comment
@kakubei Есть несколько причин, по которым это может происходить. Ваш терминал может не поддерживать UTF8, или ваша среда оболочки LANG может быть настроена неправильно. Возможно, вы захотите опубликовать вопрос о суперпользователе или новый вопрос о стеке. Однако это также может исправить ситуацию: запустите irb так: irb -E UTF-8. - person Casper; 11.02.2013
comment
Обратите внимание, что вы можете сгенерировать регулярное выражение для примера gsub: re = Regexp.union(character_table.keys); "ŠšŽžÐ".gsub(re, character_table). - person steenslag; 11.02.2013
comment
@steenslag - Хорошо. Добавлено, чтобы ответить также. Спасибо. - person Casper; 11.02.2013
comment
Все еще работаю над тем, чтобы консоль принимала специальные символы. Даже с irb -E UTF-8. Опубликую еще один вопрос для него, спасибо. - person kakubei; 12.02.2013

Это работает так, как, я полагаю, вы хотели бы: переводить символы в массиве и оставлять те, которых нет, такими, какие они есть:

# encoding: utf-8
lookup = {'Š'=>'S', 'š'=>'s', 'Ð'=>'Dj','Ž'=>'Z', 'ž'=>'z', 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A',
        'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E', 'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I',
        'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U',
        'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss','à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a',
        'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i',
        'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u',
        'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b', 'ÿ'=>'y', 'ƒ'=>'f'}

clean_genre = entry["genre"].chars.to_a.map { |x|
  if lookup.has_key?(x)
    lookup[x]
  else
    x
  end
}.join

например это:

'aŠšŽž'.chars.to_a.map { |x|
  if lookup.has_key?(x)
    lookup[x]
  else
    x
  end
}.join

дает вам «ассзз».

Или переместите логику блока в саму таблицу поиска (спасибо steenslag за упрощение решения процедуры по умолчанию!):

lookup.default_proc = proc { |hash, key| key }

тогда вызов будет выглядеть следующим образом:

puts 'aŠšŽž'.chars.to_a.map { |x| lookup[x] }.join

Или даже лучше (еще раз спасибо steenslag за указание):

puts 'aŠšŽž'.gsub(/./) { |x| lookup[x] }
person Tomasz Stanczak    schedule 11.02.2013
comment
default_proc хэша запускается по определению, когда ключ не найден; нет необходимости проверять это. lookup.default_proc = proc{|_, key| key} достаточно. - person steenslag; 11.02.2013
comment
Кроме того, с такой таблицей поиска (с default_proc) вы могли бы сделать: puts 'aŠšŽž'.gsub(/./){ |x| lookup[x] }. - person steenslag; 11.02.2013