拆分Ruby字符串时如何保留分隔符?

我有这样的文字:

content = "Do you like to code? How I love to code! I'm always coding." 

我试图把它拆分成一个?. 或者!

 content.split(/[?.!]/) 

当我打印出结果时,标点符号分隔符丢失了。

你喜欢编码吗?

我多喜欢编码

我总是在编码

我怎样才能保留标点符号?

回答

在括号捕获组内使用正向lookbehind正则表达式(即?<= ),以将分隔符保留在每个字符串的末尾:

 content.split(/(?<=[?.!])/) # Returns an array with: # ["Do you like to code?", " How I love to code!", " I'm always coding."] 

这会在第二和第三个字符串的开头留下一个空格。 在捕获组之后添加零个或多个空格( \s* )的匹配项以将其排除:

 content.split(/(?<=[?.!])\s*/) # Returns an array with: # ["Do you like to code?", "How I love to code!", "I'm always coding."] 

补充说明

虽然对于您的示例没有意义,但是分隔符可以从第二个开始移动到字符串的前面。 这是通过积极的先行正则表达式(即?= )完成的。 为了寻找这种技术的人,以下是如何做到这一点:

 content.split(/(?=[?.!])/) # Returns an array with: # ["Do you like to code", "? How I love to code", "! I'm always coding", "."] 

一个更好的例子来说明这种行为:

 content = "- the - quick brown - fox jumps" content.split(/(?=-)/) # Returns an array with: # ["- the ", "- quick brown ", "- fox jumps"] 

请注意,由于只有一个分隔符,因此不需要方括号捕获组。 此外,由于第一个匹配发生在第一个字符,它最终成为数组中的第一个项目。

要回答问题的标题,在拆分正则表达式中添加捕获组将保留拆分分隔符:

 "Do you like to code? How I love to code! I'm always coding.".split /([?!.])/ => ["Do you like to code", "?", " How I love to code", "!", " I'm always coding", "."] 

从那里开始,重建句子非常简单(或者在问题需要时进行其他按摩):

 s.split(/([?!.])/).each_slice(2).map(&:join).map(&:strip) => ["Do you like to code?", "How I love to code!", "I'm always coding."] 

然而,在其他答案中给出的正则表达确实更简洁地完成了问题的主体。

我会使用类似的东西:

 content.scan(/.+?[?!.]/) # => ["Do you like to code?", " How I love to code!", " I'm always coding."] 

如果您想摆脱干预空间,请使用:

 content.scan(/.+?[?!.]/).map(&:lstrip) # => ["Do you like to code?", "How I love to code!", "I'm always coding."] 

使用partition 。 文档中的一个示例:

 "hello".partition("l") #=> ["he", "l", "lo"] 

最强大的方法是使用自然语言处理库: Rails gem将段落分成一系列句子

您还可以分组:

 @content.split(/(\?+)|(\.+)|(!+)/) 

分成组后,您可以加入句子和分隔符。

 @content.split(/(\?+)|(\.+)|(!+)/).each_slice(2) {|slice| puts slice.join}