如何在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 的来源 发布者: 2008 年 10 月 22 日

回应 (16)


2

132932 作者的声誉

您可能需要Unicode分解(“NFD”)。分解字符串后,只需过滤掉[A-Za-z]中没有的内容。æ将分解为“ae”,ã到“a~”(大约 - 变音将成为一个单独的字符),因此过滤留下了合理的近似值。

作者: MSalters 发布者: 22.10.2008 12:14

1

5041 作者的声誉

3

31876 作者的声誉

将文本转换为规范化形式D,删除具有unicode类别非间距标记(Mn)的所有代码点,并将其转换回规范化形式C.这将删除所有变音符号,并且您的问题将简化为不区分大小写的搜索。

有关详细信息,请参见http://www.siao2.com/2005/02/19/376617.aspxhttp://www.siao2.com/2007/05/14/2629747.aspx

作者: CesarB 发布者: 22.10.2008 02:52

7

5929 作者的声誉

我认为你可能不会真正走下那条道路。如果您正在开发具有这类信件的市场,您的用户可能会认为您是一种...... 点子。因为'å'在用户的任何意义上都不接近'a'。走另一条路,阅读非ascii方式的搜索。这只是有人发明unicode和整理的案例之一。

一个很晚的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_textoriginal_text。使用original_text用于显示和canonical_text进行搜索。这样,如果用户搜索“Visual Cafe”,她会看到“VisualCafé”结果。如果她真的想要一个名为“Visual Cafe”的不同项目,它可以单独保存。

要在Ruby 1.8源文件中获取canonical_text字符,请执行以下操作:

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 with tilda”单个字符被分成n后跟一个组合变音符号的tilda字符),然后该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 gem似乎是一个很好的替代品:

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作为你的数据库适配器,也许你可以添加一个迁移它的“unaccent”扩展,我认为做你想要的,如下所示:

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数据类型。以下是对这两种方法的讨论。另请注意,建议不要使用PosgreSQL的lower()函数。

这将节省一些数据库空间,因为您将不再需要cannonical_name字段,并且可能使您的模型更简单,代价是每个查询中的一些额外处理,其数量取决于您使用的是iLIKE还是citext,以及你的数据集。

如果您使用MySQL,也许您可以使用这个简单的解决方案,但我还没有测试过它。

作者: user2553863 发布者: 08.12.2018 09:06
32x32