Вопрос:

Как заменить ударные латинские буквы в Ruby?

ruby-on-rails ruby activerecord unicode utf-8

38617 просмотра

16 ответа

37867 Репутация автора

У меня есть 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 в мой код. Фактические регулярные выражения будут выглядеть намного ужаснее.

Автор: James A. Rosen Источник Размещён: 22.10.2008 12:03

Ответы (16)


2 плюса

132932 Репутация автора

Вы, вероятно, хотите декомпозицию Unicode ("NFD"). После разложения строки просто отфильтруйте все, что не в [A-Za-z]. æ будет разложен на «ae», ã на «a ~» (приблизительно - диакритический знак станет отдельным символом), поэтому фильтрация оставляет разумное приближение.

Автор: MSalters Размещён: 22.10.2008 12:14

1 плюс

5041 Репутация автора

Iconv:

http://groups.google.com/group/ruby-talk-google/browse_frm/thread/8064dcac15d688ce ?

=============

модуль Perl, который я не могу понять:

http://www.ahinea.com/en/tech/accented-translate.html

============

грубая сила (там много тварей!

http://projects.jkraemer.net/acts_as_ferret/wiki#UTF-8support

http://snippets.dzone.com/posts/show/2384

Автор: Gene T Размещён: 22.10.2008 12:50

3 плюса

31876 Репутация автора

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

См. Http://www.siao2.com/2005/02/19/376617.aspx и http://www.siao2.com/2007/05/14/2629747.aspx для получения подробной информации.

Автор: CesarB Размещён: 22.10.2008 02:52

7 плюса

5929 Репутация автора

Я думаю, что вы, возможно, не совсем то, что идти по этому пути. Если вы разрабатываете для рынка с такими буквами, ваши пользователи, вероятно, подумают, что вы что-то вроде ... пипс . Потому что «å» даже не близко к «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/

Автор: Jonke Размещён: 23.10.2008 07:41

55 плюса

2009 Репутация автора

Решение

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

>> "àáâãäå".mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.to_s
=> "aaaaaa"
Автор: unexist Размещён: 15.11.2008 02:18

3 плюса

37867 Репутация автора

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

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

register_replacement([0x008A].pack('U'), 'S')
Автор: James A. Rosen Размещён: 23.01.2009 06:59

-3 плюса

0 Репутация автора

лол .. я просто попробовал это .. и он работает .. я все еще не совсем уверен, почему .. но когда я использую это 4 строки кода:

  • str = str.gsub (/ [^ a-zA-Z0-9] /, "")
  • str = str.gsub (/ [] + /, "")
  • str = str.gsub (/ /, "-")
  • str = str.downcase

он автоматически удаляет любой акцент из имен файлов .. который я пытался удалить (ударение из имен файлов и переименовывает их, чем) надеюсь, что это помогло :)

Автор: Jozef Размещён: 29.03.2009 08:02

1 плюс

10666 Репутация автора

Для тех, кто читает это и хочет убрать все не-ascii символы, это может быть полезно, я успешно использовал первый пример.

Автор: Kris Размещён: 29.08.2010 12:48

83 плюса

1455 Репутация автора

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

пример:

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

Автор: Mark Wilden Размещён: 23.08.2011 11:47

5 плюса

2463 Репутация автора

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

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

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

# coding: utf-8

normalize(:kd)часть здесь распадается из диакритических , где это возможно (например: «N с Тильдой» одного символом расщепляется в п сопровождаемого диакритической Тильды характером), а gsubчасть удаляет все диакритические знаки.

Автор: Cheng Размещён: 15.01.2012 03:37

18 плюса

21569 Репутация автора

Я пробовал многие из этих подходов, но они не достигли одного или нескольких из этих требований:

  • Респект Пространства
  • Уважение к персонажу
  • Уважать регистр (я знаю, что это не является обязательным требованием для первоначального вопроса, но нетрудно переместить строку в нижний регистр )

Было это:

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

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

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

Автор: fguillen Размещён: 10.09.2012 02:43

0 плюса

25 Репутация автора

У меня были проблемы с получением решения foo.mb_chars.normalize (: kd) .gsub (/ [^ \ x00- \ x7F] / n, ''). Downcase.to_s. Я не использую Rails, и у меня были некоторые конфликты с моими версиями activesupport / ruby, до которых я не смог добраться до сути.

Использование камня ruby-unf кажется хорошей заменой:

require 'unf'
foo.to_nfd.gsub(/[^\x00-\x7F]/n,'').downcase

Насколько я могу судить, это делает то же самое, что и .mb_chars.normalize (: kd). Это правильно? Спасибо!

Автор: eoghan.ocarragain Размещён: 19.09.2012 11:04

4 плюса

10752 Репутация автора

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

"anything".parameterize.underscore.humanize.downcase

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

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

Автор: Sudhir Jonathan Размещён: 29.04.2013 07:54

10 плюса

12563 Репутация автора

Мой ответ: метод 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"
Автор: Dorian Размещён: 23.07.2013 12:07

38 плюса

381 Репутация автора

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

1.9.3-p392 :001 > require "i18n"
 => false
1.9.3-p392 :002 > I18n.transliterate("Olá Mundo!")
 => "Ola Mundo!"
Автор: Diego Moreira Размещён: 14.12.2013 06:33

0 плюса

160 Репутация автора

Если вы используете PostgreSQL => 9.4 в качестве адаптера БД, возможно, вы могли бы добавить в миграцию его «неприличное» расширение, которое, я думаю, выполняет то, что вы хотите, например:

def self.up
   enable_extension "unaccent" # No falla si ya existe
end

Для тестирования в консоли:

2.3.1 :045 > ActiveRecord::Base.connection.execute("SELECT unaccent('unaccent', 'àáâãäåÁÄ')").first
 => {"unaccent"=>"aaaaaaAA"}

Обратите внимание, что до сих пор учитывается регистр.

Затем, возможно, используйте его в области видимости, например:

scope :with_canonical_name, -> (name) {
   where("unaccent(foos.name) iLIKE unaccent('#{name}')")
}

Оператор iLIKE делает регистр поиска нечувствительным. Существует другой подход, использующий тип данных citext . Вот обсуждение этих двух подходов. Обратите также внимание на то, что использование функции lower () в PosgreSQL не рекомендуется .

Это сэкономит вам некоторое пространство БД, поскольку вам больше не потребуется поле cannonical_name и, возможно, сделает вашу модель проще, за счет некоторой дополнительной обработки в каждом запросе, в размере, зависящем от того, используете ли вы iLIKE или citext, и ваш набор данных.

Если вы используете MySQL, возможно, вы можете использовать это простое решение , но я не проверял его.

Автор: user2553863 Размещён: 08.12.2018 09:06
Вопросы из категории :
32x32