【问题标题】:Remove spaces (apostrophes) around quotes with regex in ruby在ruby中使用正则表达式删除引号周围的空格(撇号)
【发布时间】:2020-12-28 07:19:16
【问题描述】:

我正在尝试使用一个 Ruby 正则表达式删除引号周围的所有空格。 (和this不是同一个问题)

  • 输入:l' avant ou l 'après ou encore 'maintenant'
  • 输出:l'avant ou l'après ou encore 'maintenant'

我尝试了什么:

(/'\s|\s'/, '')

它匹配少数情况,但不是全部。 如何执行此操作?谢谢。

【问题讨论】:

  • 尝试将/\b'\s\b/替换为'
  • 你好维克托。它只匹配句子中的 1 个结果...
  • 什么意思? s.gsub(/\b'\s\b/, "'")?
  • 拥有encore ' maintenant的规则是什么?
  • 规则是去掉引号后、单词前的空格 => encore 'maintenant'

标签: regex ruby


【解决方案1】:

TLDR:

我假设空格是由某些自动化软件插入的,并且单词周围只能有单个空格。

s = "l' avant ou l 'apres ou encore ' maintenant' ou bien 'ceci ' et ' encore de l ' huile ' d 'accord d' accord d ' accord Je n' en ai pas .... s ' entendre Je m'appelle Victor"
first_rx = /(?<=\b[b-df-hj-np-tv-z]) ' ?(?=\p{L})|(?<=\b[b-df-hj-np-tv-z]) ?' (?=\p{L})/i
# If you find it overmatches, replace [b-df-hj-np-tv-z] with [dlnsmtc], 
# i.e. first letters of word that are usually contracted
second_rx = /\b'\b\K|' *((?:\b'\b|[^'])+)(?<=\S) *'/
puts s.gsub(first_rx, "'")
      .gsub(second_rx) { $~[1] ? "'#{$~[1]}'" : "" }    

输出:

l'avant ou l'apres ou encore 'maintenant' ou bien 'ceci' et 'encore de l'huile' d'accord d'accord d'accord Je n'en ai pas .... s'entendre Je m'appelle Victor

说明

这个问题真的很复杂。有几个单词可以缩写并与法语中的撇号一起使用,dele/lanesemetece 仅举几例,但这些都是辅音。您可以使用

删除单个独立辅音、撇号和下一个单词之间的所有空格
s.gsub(/(?<=\b[b-df-hj-np-tv-z]) ' ?(?=\p{L})|(?<=\b[b-df-hj-np-tv-z]) ?' (?=\p{L})/i, "'")

如果您发现它过度匹配,请将 [b-df-hj-np-tv-z] 替换为 [dlnsmtc],即通常缩写的单词的第一个字母。请参阅regex demo

下一步是删除首字母之后和尾随撇号之前的空格。这很棘手:

s.gsub(/\b'\b\K|' *((?:\b'\b|[^'])+)(?<=\S) *'/) { $~[1] ? "'#{$~[1]}'" : "" }

其中\b'\b 旨在匹配单词字符之间的所有撇号,我们在上一步中修复的那些。见this regex demo。由于 Onigmo 正则表达式中没有 (*SKIP)(*F) 支持,正则表达式有点简化,但替换是有条件的:如果组 1 匹配,则替换为 ' + 组 1 值 ($1) + ',否则,替换为空字符串(因为\K 重置匹配,从匹配内存缓冲区中删除所有文本)。

注意:这种方法也可以扩展到处理一些特定情况,例如aujourd'hui

【讨论】:

  • 这涵盖了很多情况,应该是公认的答案。
  • 你好维克托。感谢您提供涵盖许多案例的详细答案。这将是我扩展它的基础。正如您所说,问题很复杂,而且更复杂,因为我还有其他语言要管理(例如意大利语中的“Dell'a”)。
【解决方案2】:

要删除' 周围的所有空格,请使用gsub!,通过几个步骤应用以正确删除空格:

str = "l' avant ou l 'apres ou encore ' maintenant'"
str.gsub!(/\b'\s+\b/, "'").gsub!(/\b\s+'\b/, "'").gsub!(/\b(\s+')\s+\b/, '\1')
puts str
# l'avant ou l'apres ou encore 'maintenant'

这里,
\b:单词边界,
\s+:1个或多个空格,
string.gsub!(regex, replacement_string):将string参数regex替换为指定的replacement_string(在此期间,原来的string 被更改),
\1 :在替换字符串中,这指的是正则表达式中括号中捕获的第一组:(...)

【讨论】:

  • 就我而言,当引号位于两个引号之间的单词之前的两个空格之间时,它不起作用。在这种 uniq 案例中,它匹配引号之前的空格,而不是之后的空格。见那里:rubular.com/r/IgItrVEvuaLfKs
  • @alex.bour 固定
  • 非常好的帖木儿!情况更复杂。它适用于我的情况。但是,最后一件事(对不起)。我会试试这个:" l' avant ou l 'apres ou encore ' maintenant' ou bien 'ceci ' "我需要增强最后一个新案例(单词后和引号前的空格)。
  • @alex.bour 请编辑问题并添加这个,加上想要的结果,这样每个人都可以轻松看到它。否则,很难看到。此外,根据所需的结果,对于边缘情况,可能值得在问题中指定撇号应该去哪里的规则。
【解决方案3】:

因此,如果您有很多这样的数据,那么我看到的所有答案都是错误的,并且不起作用。 没有正则表达式可以猜测前面的单词是否应该有空格。除非你想出了一个可以做或不做的单词(或模式)列表。

问题是,有时应该留一个空格,有时则不。编写脚本的唯一方法是找到一个模式,该模式描述何时应该有空间,或者什么时候不应该。你必须教你的正则表达式法语语法。这可能是可能的大声笑。但可能不会,或者很难。

如果这是一次性的,我的建议是为 2 或 3 种不同的情况创建正则表达式,并使用 vim 之类的工具来检查数据,然后手动选择是或否来替换每次出现的情况。

在某些情况下您可以运行 - 例如删除引号右侧的所有空格? - 但不幸的是,我认为你不能自动化这个过程。

【讨论】:

    【解决方案4】:

    我相信以下内容应该适合你

    s.gsub(/'.*?'/){ |e| "'#{e[1...-1].strip}'" }
    

    正则表达式部分惰性匹配单引号内的所有文本(包括引号)。然后,对于每个匹配项,您都用删除了前导和尾随空格的引用文本替换,并在引号中返回此文本。

    【讨论】:

    • 嗨罗伯特。不,它匹配 word ' test ' 时引号周围的 2 个空格,但应该让 1。
    • 哦,我明白你的意思了,然后让我做一些改变
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-09
    • 2016-02-08
    • 1970-01-01
    • 2014-08-22
    • 1970-01-01
    • 1970-01-01
    • 2013-01-13
    相关资源
    最近更新 更多