Как заменить акцентированные латинские символы в Ruby? - PullRequest
69 голосов
/ 22 октября 2008

У меня есть модель ActiveRecord, Foo, которая имеет поле name. Я бы хотел, чтобы пользователи могли выполнять поиск по имени, но я бы хотел, чтобы поиск игнорировал регистр и любые акценты. Таким образом, я также храню поле canonical_name для поиска:

class Foo
  validates_presence_of :name

  before_validate :set_canonical_name

  private

  def set_canonical_name
    self.canonical_name ||= canonicalize(self.name) if self.name
  end

  def canonicalize(x)
    x.downcase.  # something here
  end
end

Мне нужно заполнить «что-то здесь», чтобы заменить акцентированные символы. Есть ли что-нибудь лучше, чем

x.downcase.gsub(/[àáâãäå]/,'a').gsub(/æ/,'ae').gsub(/ç/, 'c').gsub(/[èéêë]/,'e')....

И, кстати, поскольку я не на Ruby 1.9, я не могу вставить эти литералы Unicode в мой код. Фактические регулярные выражения будут выглядеть намного ужаснее.

Ответы [ 16 ]

86 голосов
/ 23 августа 2011

ActiveSupport::Inflector.transliterate (требуется Rails 2.2.1+ и Ruby 1.9 или 1.8.7)

пример:

>> ActiveSupport::Inflector.transliterate("àáâãäå").to_s => "aaaaaa"

57 голосов
/ 15 ноября 2008

В Rails уже есть встроенная функция для нормализации, вы просто должны использовать ее для нормализации вашей строки, чтобы сформировать KD, а затем удалить другие символы (то есть знаки ударения), например:

>> "àáâãäå".mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.to_s
=> "aaaaaa"
38 голосов
/ 14 декабря 2013

Еще лучше использовать I18n:

1.9.3-p392 :001 > require "i18n"
 => false
1.9.3-p392 :002 > I18n.transliterate("Olá Mundo!")
 => "Ola Mundo!"
18 голосов
/ 10 сентября 2012

Я испробовал много таких подходов, но они не выполняли одно или несколько из следующих требований:

  • Респект пробелы
  • Уважать символ 'ñ'
  • Respect case (я знаю, что это не является обязательным требованием для исходного вопроса, но не сложно переместить строку в lowcase )

Было ли это:

# coding: utf-8
string.tr(
  "ÀÁÂÃÄÅàáâãäåĀāĂ㥹ÇçĆćĈĉĊċČčÐðĎďĐđÈÉÊËèéêëĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħÌÍÎÏìíîïĨĩĪīĬĭĮįİıĴĵĶķĸĹĺĻļĽľĿŀŁłÑñŃńŅņŇňʼnŊŋÒÓÔÕÖØòóôõöøŌōŎŏŐőŔŕŖŗŘřŚśŜŝŞşŠšſŢţŤťŦŧÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųŴŵÝýÿŶŷŸŹźŻżŽž",
  "AAAAAAaaaaaaAaAaAaCcCcCcCcCcDdDdDdEEEEeeeeEeEeEeEeEeGgGgGgGgHhHhIIIIiiiiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnNnnNnOOOOOOooooooOoOoOoRrRrRrSsSsSsSssTtTtTtUUUUuuuuUuUuUuUuUuUuWwYyyYyYZzZzZz"
)

- http://blog.slashpoundbang.com/post/12938588984/remove-all-accents-and-diacritics-from-string-in-ruby

Вы должны немного изменить список символов, чтобы он соответствовал символу '-', но это простая работа.

10 голосов
/ 23 июля 2013

Мой ответ: метод String # параметризация :

"Le cœur de la crémiére".parameterize
=> "le-coeur-de-la-cremiere"

Для не-Rails программ:

Установить activesupport: gem install activesupport затем:

require 'active_support/inflector'
"a&]'s--3\014\xC2àáâã3D".parameterize
# => "a-s-3-3d"
7 голосов
/ 23 октября 2008

Я думаю, что вы, возможно, не совсем то, что идти по этому пути. Если вы разрабатываете для рынка с такими буквами, ваши пользователи, вероятно, подумают, что вы что-то вроде ... pip . Потому что «å» даже не близко к «a» в каком-либо смысле для пользователя. Выбери другую дорогу и прочитай о поиске не ascii способом. Это только один из тех случаев, когда кто-то изобрел юникод и сопоставление .

Очень поздно PS :

http://www.w3.org/International/wiki/Case_folding http://www.w3.org/TR/charmod-norm/#sec-WhyNormalization

Кроме того, у меня нет идеального пути, чтобы ссылка на сопоставление пошла на страницу msdn, но я оставляю ее там. Это должно было быть http://www.unicode.org/reports/tr10/

6 голосов
/ 15 января 2012

Разложите строку и удалите непропускные метки из нее.

irb -ractive_support/all
> "àáâãäå".mb_chars.normalize(:kd).gsub(/\p{Mn}/, '')
aaaaaa

Вам также может понадобиться это при использовании в файле .rb.

# coding: utf-8

часть normalize(:kd) здесь разделяет диакритические знаки, где это возможно (например, одиночный символ "n с тильдой" разделяется на n, за которым следует объединенный диакритический символ тильды), а часть gsub затем удаляет все диакритические знаки символы.

4 голосов
/ 29 апреля 2013

Предполагается, что вы используете Rails.

"anything".parameterize.underscore.humanize.downcase

Учитывая ваши требования, это, вероятно, то, что я бы сделал ... Я думаю, что это аккуратно, просто и будет соответствовать последним версиям Rails и Ruby.

Обновление: dgilperez указал, что parameterize принимает аргумент-разделитель, поэтому "anything".parameterize(" ") (устарело) или "anything".parameterize(separator: " ") короче и чище.

3 голосов
/ 23 января 2009

Ключ должен использовать два столбца в вашей базе данных: canonical_text и original_text. Используйте original_text для отображения и canonical_text для поиска. Таким образом, если пользователь ищет «Визуальное кафе», он видит результат «Визуальное кафе». Если она действительно хочет другой элемент под названием «Визуальное кафе», его можно сохранить отдельно.

Чтобы получить символы canonical_text в исходном файле Ruby 1.8, сделайте что-то вроде этого:

register_replacement([0x008A].pack('U'), 'S')
3 голосов
/ 22 октября 2008

Преобразование текста в форму нормализации D, удаление всех кодовых точек с меткой без пробелов категории Unicode (Mn) и преобразование ее обратно в форму нормализации C. Это исключит все диакритические знаки, и ваша проблема будет сведена к поиску без учета регистра.

Подробнее см. http://www.siao2.com/2005/02/19/376617.aspx и http://www.siao2.com/2007/05/14/2629747.aspx.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...