Ruby 正则表达式消除新行直到 .要么 ?或大写字母

Ruby regex eliminate new line until . or ? or capital letter

我想用我的琴弦做以下事情:

line1= "You have a house\nnext to the corner."

如果句子在点或问号或大写字母后没有换行结束,则消除 \n,因此在这种情况下所需的输出将是:

"You have a house next to the corner.\n"

再举一个例子,这次是问号:

"You like baggy trousers,\ndon't you?

应该变成:

"You like baggy trousers, don't you?\n".

我试过:

line1.gsub!(/(?<!?|.)"\n"/, " ") 

(?<!?|.) \n 之前不能有问号(?)或逗号

但我收到以下语法错误:

SyntaxError: (eval):2: target of repeat operator is not specified: /(?<!?|.)"\n"/

对于中间有大写字母的句子,在大写字母前加一个\n,所以句子:

"We were winning The Home Secretary played a important role." 

应该变成:

"We were winning\nThe Home Secretary played a important role." 

你快到了。您需要 a) 转义 ?. 和 b) 删除表达式中 \n 周围的引号:

line1= "You have a house\nnext to the corner.\nYes?\nNo."
line1.gsub!(/(?<!\?|\.)\s*\n\s*/, " ")
#⇒ "You have a house next to the corner.\nYes?\nNo."

如你所愿的尾部\n,后面加上即可:

line1.gsub! /\Z/, "\n"
#⇒ "You have a house next to the corner.\nYes?\nNo.\n"

实现此目的的简单方法是用 space 替换所有嵌入的换行符,这样可以有效地连接线段,然后修复行尾。没有必要担心标点符号,也没有必要使用(或维护)正则表达式。

你可以用很多方法来做到这一点,但我会使用:

sentences = [
  "foo\nbar",
  "foo\n\nbar",
  "foo\nbar\n",
]

sentences.map{ |s| s.gsub("\n", ' ').squeeze(' ').strip + "\n" }
# => ["foo bar\n", "foo bar\n", "foo bar\n"]

下面是 map 块中发生的事情:

s                # => "foo\nbar", "foo\n\nbar", "foo\nbar\n"
.gsub("\n", ' ') # => "foo bar", "foo  bar", "foo bar "
.squeeze(' ')    # => "foo bar", "foo bar", "foo bar "
.strip           # => "foo bar", "foo bar", "foo bar"
+ "\n"           

注意:答案并不意味着提供一种通用的方法来删除句子中不必要的换行符,它只是为了服务于 OP 目的,只删除或插入换行符字符串中的特定位置。

由于在不同的场景下需要以不同的方式替换匹配项,因此您应该考虑采用两步法。

.gsub(/(?<![?.])\n/, ' ')

这个将替换所有没有以 ?. 开头的换行符(因为 (?<![?.]) 是一个否定的后视,如果在当前的之前有一个子模式匹配,则匹配失败字符串内的位置)。

第二步是

.sub(/(?<!^) *+(?=[A-Z])/, '\n')

.sub(/(?<!^) *+(?=\p{Lu})/, '\n')

它将匹配不在行首的 0+ spaces ( *+)(当然,不会回溯到 space 模式)(由于(?<!^) negative lookbehind,将 ^ 替换为 \A 以匹配整个字符串的开头),然后是一个大写字母((?=\p{Lu}) 是一个正 lookahead,需要在当前位置右侧出现的图案)。