如何在Ruby中replace重音拉丁字符?

我有一个ActiveRecord模型, Foo ,它有一个name字段。 我希望用户能够按名称search,但我希望search忽略大小写和任何重音符号。 因此,我还存储了一个canonical_name字段来search:

 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文字放在我的代码中。 实际的正则expression式看起来更丑陋。

Rails已经有一个内置的标准化,你只需要使用这个标准化你的string来形成KD,然后删除其他字符(即重音符号),如下所示:

 >> "àáâãäå".mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.to_s => "aaaaaa" 

ActiveSupport::Inflector.transliterate (需要Rails 2.2.1+和Ruby 1.9或1.8.7)

例:

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

更好的是使用I18n:

 1.9.3-p392 :001 > require "i18n" => false 1.9.3-p392 :002 > I18n.transliterate("Olá Mundo!") => "Ola Mundo!" 

我已经尝试了很多这种方法,但他们没有达到这些要求中的一个或几个:

  • 尊重空间
  • 尊重''字符
  • 尊重案件(我知道是不是原来的问题的要求,但不难将string移动到小写

一直是这样的:

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

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

你必须修改一些字符列表来尊重'ñ'字符,但是很容易。

我想你可能真的不知道该怎么走。 如果你正在开发一个有这种信件的市场,你的用户可能会认为你是一种… 点子 。 因为对于用户来说,''甚至不是接近于'a'。 采取不同的道路,并阅读有关search非ascii的方式。 这只是有人发明unicode和整理的情况之一 。

非常晚PS

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

除此之外,我没有ide的方式链接到整理去msdn页面,但我离开它。 它应该是http://www.unicode.org/reports/tr10/

我的回答: String#parameterize方法:

 "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 # => "as-3-3d" 

分解string并从中删除非间距标记 。

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

如果在.rb文件中使用,您可能还需要这个。

 # coding: utf-8 

在这里, normalize(:kd)部分在可能的情况下分开变音符号(例如:“n with tilda”单个字符被分割成n,然后是组合变音符tilda字符),然后gsub部分删除所有变音符号。

这假定你使用Rails。

 "anything".parameterize.underscore.humanize.downcase 

根据你的要求,这可能是我会做的…我认为它是整洁,简单,并保持最新的Rails和Ruby的未来版本。

更新:dgilperez指出parameterize需要一个分隔符参数,所以"anything".parameterize(" ") (不推荐)或"anything".parameterize(separator: " ")更短,更干净。

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

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

关键是在数据库中使用两列: canonical_textoriginal_text 。 使用original_text进行显示,使用canonical_text进行search。 这样,如果用户search“视觉咖啡馆”,她看到“视觉咖啡厅”结果。 如果她真的想要一个名为“Visual Cafe”的不同的项目,可以单独保存。

要获得Ruby 1.8源文件中的canonical_text字符,请执行如下操作:

 register_replacement([0x008A].pack('U'), 'S') 

你可能想要Unicode分解(“NFD”)。 分解string后,只需过滤掉[A-Za-z]中的任何内容。 将分解为“ae”,“a〜”(大约 – 分隔符将成为一个单独的字符),所以过滤留下合理的近似值。

对于任何读这个想要去掉所有非ASCII字符的人来说, 这可能是有用的,我成功地使用了第一个例子。

我有问题得到foo.mb_chars.normalize(:kd).gsub(/ [^ \ x00- \ x7F] / n,'')。downcase.to_s解决scheme的工作。 我没有使用Rails,与我的主动支持/ruby版本有一些冲突,我无法理解。

使用ruby-unfgem似乎是一个很好的替代品:

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

据我所知,这和.mb_chars.normalize(:kd)是一样的。 它是否正确? 谢谢!

大声笑..我刚试了这个..它是工作..我还是不太确定为什么..但是当我使用这4行代码:

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

它自动从文件名删除任何口音..我试图删除(口音从文件名和重命名比)希望它帮助:)