草庐IT

Ruby super 不敏感的正则表达式,用于将学校名称与重音符号和其他变音符号匹配

coder 2023-10-30 原文

这个问题已经在其他编程语言中被问到,但是你将如何在 Ruby 上执行不区分重音的正则表达式?

我现在的代码是这样的

scope :by_registered_name, ->(regex){
  where(:name => /#{Regexp.escape(regex)}/i)
}

我想也许我可以用点替换非字母数字+空白字符,并删除 escape ,但是有没有更好的办法呢?如果我这样做,恐怕我会抓到奇怪的东西......

我现在的目标是法语,但如果我也能针对其他语言修复它,那就太棒了。

如果有帮助,我正在使用 Ruby 2.3。


我意识到我的要求实际上有点强,我还需要捕捉破折号等东西。我基本上是在导入一个学校数据库( URL here ,标签是 <nom> ),我希望人们成为能够通过输入学校名称找到他们的学校。搜索查询和搜索请求都可能包含重音符号,我认为最简单的方法是使“两者”不敏感。

  • “Télécom”应匹配“Telecom”
  • “établissement”应与“etablissement”匹配
  • “Institut supérieur national de l'artisanat - Chambre de métiers et de l'Artisanat en Moselle”应与“artisanat chambre de métiers”相匹配
  • “Ecole hôtelière d'Avignon (CCI du Vaucluse)”应与 Ecole hoteliere d'avignon 匹配(对于括号可以跳过它)
  • “Ecole française d'hôtesses”应与“ecole francaise d'hot”匹配

我在那个数据库中发现了一些疯狂的东西,我会考虑清理我认为的这个输入

  • “Académie internationale de management - Hotel & Tourism Management Academy”应与“Hotel Tourism”匹配(注意 & 实际上在 XML 中写为 &amp;)

最佳答案

看起来 MongoDB 的解决方案是使用 text index ,即 diacritic insensitive .法语是supported .

自从我上次使用 MongoDB 以来已经有很长时间了,但是如果您使用 Mongoid,我想您会像这样在您的模型中创建一个 text 索引:

index(name: "text")

...然后像这样搜索:

scope :by_registered_name, ->(str) {
  where(:$text => { :$search => str })
}

查阅 $text query operator 的文档获取更多信息。

原始(错误)答案

As it turns out I was thinking about the question backwards, and wrote this answer initially. I'm preserving it since it might still come in handy. If you were using a database that didn't offer this kind of functionality (like, it seems, MongoDB does), a possible workaround would be to use the following technique to store a sanitized name along with the original name in the database, and then likewise sanitize queries.

由于您使用的是 Rails,因此您可以使用方便的 ActiveSupport::Inflector.transliterate :

regex = /aäoöuü/
transliterated = ActiveSupport::Inflector.transliterate(regex.source, '\?')
# => "aaoouu"
new_regex = Regexp.new(transliterated)
# => /aaoouu/

或者简单地说:

Regexp.new(ActiveSupport::Inflector.transliterate(regex.source, '\?'))

您会注意到我提供了 '\?' 作为第二个参数,这是将替换任何无效 UTF-8 字符的替换字符串。这是因为默认的替换字符串是 "?",如您所知,它在正则表达式中具有特殊含义。

另请注意,ActiveSupport::Inflector.transliterate 比类似的 I18n.transliterate 做的多一点。这是它的来源:

def transliterate(string, replacement = "?")
  I18n.transliterate(ActiveSupport::Multibyte::Unicode.normalize(
    ActiveSupport::Multibyte::Unicode.tidy_bytes(string), :c),
      :replacement => replacement)
end

最内层的方法调用,ActiveSupport::Multibyte::Unicode.tidy_bytes , 清除任何无效的 UTF-8 字符。

更重要的是,ActiveSupport::Multibyte::Unicode.normalize “规范化”字符。例如,ê 看起来像一个字符,但实际上是两个字符:拉丁小写字母 E 和 COMBINING CIRCUMFLEX ACCENT。调用 I18n.transliterate("ê") 会产生 e?,这可能不是您想要的,因此调用 normalize 以转ê 转换为 ê,这只是一个字符:带有 CIRCUMFLEX 的拉丁文小写字母 E。在 ê(前者)上调用 I18n.transliterate 会产生 e?,这可能不是您想要的,因此 transliterate 之前的 normalize 步骤很重要。 (如果您对其工作原理感兴趣,请阅读 Unicode equivalence and normalization。)

关于Ruby super 不敏感的正则表达式,用于将学校名称与重音符号和其他变音符号匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37079888/

有关Ruby super 不敏感的正则表达式,用于将学校名称与重音符号和其他变音符号匹配的更多相关文章

  1. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  2. ruby-on-rails - 标准化文件名的字符串,删除重音和特殊字符 - 2

    我正在尝试找到一种方法来规范化字符串以将其作为文件名传递。到目前为止我有这个:my_string.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.gsub(/[^a-z]/,'_')但第一个问题:-字符。我猜这个方法还有更多问题。我不控制名称,名称字符串可以有重音符、空格和特殊字符。我想删除所有这些,用相应的字母('é'=>'e')替换重音符号,并将其余的替换为'_'字符。名字是这样的:“Prélèvements-常规”“健康证”...我希望它们像一个没有空格/特殊字符的文件名:“prelevements_routin

  3. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  4. ruby - 正则表达式将非英文字母匹配为非单词字符 - 2

    @raw_array[i]=~/[\W]/非常简单的正则表达式。当我用一些非拉丁字母(具体来说是俄语)尝试时,条件是错误的。我能用它做什么? 最佳答案 @raw_array[i]=~/[\p{L}]/使用西里尔字符进行测试。引用:http://www.regular-expressions.info/unicode.html#prop 关于ruby-正则表达式将非英文字母匹配为非单词字符,我们在StackOverflow上找到一个类似的问题: https://

  5. ruby-on-rails - 应用程序的名称是否可以作为变量使用? - 2

    当我创建一个Rails应用程序时,控制台:railsnewfoo我的代码可以使用字符串“foo”吗?puts"Yourapp'snameis"+app_name_bar 最佳答案 Rails.application.class将为您提供应用程序的全名(例如YourAppName::Application)。从那里您可以使用Rails.application.class.parent获取模块名称。 关于ruby-on-rails-应用程序的名称是否可以作为变量使用?,我们在StackOve

  6. ruby-on-rails - 如何从过时的 TZInfo 标识符中获取 Rails TimeZone 名称? - 2

    已经有一个问题回答了如何将“America/Los_Angeles”转换为“PacificTime(US&Canada)”。但是我想将“美国/太平洋”和其他过时的时区转换为RailsTimeZone。我无法在图书馆中找到任何可以帮助我完成此任务的东西。 最佳答案 来自RailsActiveSupport::TimeZonedocs:TheversionofTZInfobundledwithActiveSupportonlyincludesthedefinitionsnecessarytosupportthezonesdefinedb

  7. ruby - 正则表达式在哪个位置失败? - 2

    我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

  8. ruby - 有没有办法从 ruby​​ case 语句中访问表达式? - 2

    我想从then子句中访问c​​ase语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案

  9. ruby - 正则表达式 - 排除一个字符 - 2

    这是一个例子:s="abcd+subtext@example.com"s.match(/+[^@]*/)Result=>"+subtext"问题是,我不想在其中包含“+”。我希望结果是“潜台词”,没有+ 最佳答案 您可以在正则表达式中使用括号来创建匹配组:s="abcd+subtext@example.com"s=~/\+([^@]*)/&&$1=>"subtext" 关于ruby-正则表达式-排除一个字符,我们在StackOverflow上找到一个类似的问题:

  10. ruby - 如何遍历 Ruby 中所有正则表达式匹配的字符串? - 2

    我们有一个字符串:“”这个正则表达式://i如何从当前字符串中获取所有匹配项? 最佳答案 "".scan(//)参见scan在ruby​​-docs上 关于ruby-如何遍历Ruby中所有正则表达式匹配的字符串?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/6857852/

随机推荐