【问题标题】:Split string into a list, but keeping the split pattern将字符串拆分为列表,但保留拆分模式
【发布时间】:2011-08-05 14:23:31
【问题描述】:

目前我正在按模式拆分字符串,如下所示:

outcome_array=the_text.split(pattern_to_split_by)

问题是我分割的模式本身总是被省略。

如何让它包含拆分模式本身?

【问题讨论】:

  • 你想保存两个字符串,分割的和未分割的就是你要的?
  • 你想在哪里包含模式?在字符串里面?
  • 我也希望在字符串中返回拆分模式。
  • 你能举出输入输出的例子吗?
  • @Hermann:你为什么要把'split it ''here and '拆分出来?

标签: ruby string split


【解决方案1】:

感谢 Mark Wilkins 的启发,但这里有一小段代码:

irb(main):015:0> s = "split on the word on okay?"
=> "split on the word on okay?"
irb(main):016:0> b=[]; s.split(/(on)/).each_slice(2) { |s| b << s.join }; b
=> ["split on", " the word on", " okay?"]

或:

s.split(/(on)/).each_slice(2).map(&:join)

请参阅折叠下方的说明。


这是它的工作原理。首先,我们拆分“on”,但将其包裹在括号中以使其成为匹配组。当传递给split 的正则表达式中有匹配组时,Ruby 会在输出中包含该组:

s.split(/(on)/)
# => ["split", "on", "the word", "on", "okay?"

现在我们想将“on”的每个实例与前面的字符串连接起来。 each_slice(2) 通过一次将两个元素传递给它的块来提供帮助。让我们调用each_slice(2) 来查看结果。由于each_slice,在没有块的情况下调用时,将返回一个枚举器,我们将to_a应用于枚举器,这样我们就可以看到枚举器将枚举什么:

s.split(/(on)/).each_slice(2).to_a
# => [["split", "on"], ["the word", "on"], ["okay?"]]

我们越来越近了。现在我们所要做的就是将这些词连接在一起。这让我们得到了上面的完整解决方案。我将把它展开成单独的行以便于理解:

b = []
s.split(/(on)/).each_slice(2) do |s|
  b << s.join
end
b
# => ["split on", "the word on" "okay?"]

但是有一个绝妙的方法可以消除临时的b 并大大缩短代码:

s.split(/(on)/).each_slice(2).map do |a|
  a.join
end

map 将其输入数组的每个元素传递给块;块的结果成为输出数组中该位置的新元素。在 MRI >= 1.8.7 中,您可以将其进一步缩短到等效:

s.split(/(on)/).each_slice(2).map(&:join)

【讨论】:

  • +1 非常好。我喜欢红宝石;它有简洁易读的语法。
  • @WayneConrad 非常感谢更长的解释。谢谢。
【解决方案2】:

您可以使用正则表达式断言来定位分割点,而无需消耗任何输入。下面使用肯定的后向断言在“on”之后进行拆分:

s = "split on the word on okay?"
s.split(/(?<=on)/)
=> ["split on", " the word on", " okay?"]

或者在 'on' 之前拆分的积极前瞻:

s = "split on the word on okay?"
s.split(/(?=on)/)
=> ["split ", "on the word ", "on okay?"]

有了这样的东西,你可能想确保'on'不是一个更大的单词的一部分(比如'assertion'),并在分割处删除空格:

"don't split on assertion".split(/(?<=\bon\b)\s*/)
=> ["don't split on", "assertion"]

【讨论】:

  • 可以使用这些的组合在中间进行拆分,例如:"this>)(?= ["this>", "", "
【解决方案3】:

如果您使用带有组的模式,它也会在结果中返回该模式:

irb(main):007:0> "split it here and here okay".split(/ (here) /)
=> ["split it", "here", "and", "here", "okay"]

编辑 附加信息表明目标是将其拆分的项目与拆分项目的一半之一包括在内。我认为有一种简单的方法可以做到这一点,但我不知道,今天也没有时间玩它。因此,在没有聪明的解决方案的情况下,以下是暴力破解的一种方法。使用上述split 方法将拆分项包含在数组中。然后遍历该数组并将每隔一个条目(根据定义是拆分值)与前一个条目组合。

s = "split on the word on and include on with previous"
a = s.split(/(on)/)

# iterate through and combine adjacent items together and store
# results in a second array
b = []
a.each_index{ |i|
   b << a[i] if i.even?
   b[b.length - 1] += a[i] if i.odd?
   }

print b

结果如下:

["split on", " the word on", " and include on", " with previous"]

【讨论】:

  • 'irb(main):007:0>' 是什么东西?
  • 在这种情况下,我希望将 'here' 作为它正在拆分的任一字符串的一部分。
  • @Hermann:是interactive Ruby shell。在提示符下键入“irb”,您可以即时输入 Ruby 命令。
  • @Hermann:我不知道得到它的语法。如果你有一个具体的例子,我认为使用适当的正则表达式可能是可能的。但是,仅“迭代”字符串并手动拆分它可能更简单。当我有时间时,我将不得不再考虑一下。有趣的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-23
  • 2011-02-24
  • 1970-01-01
  • 2020-09-13
  • 1970-01-01
相关资源
最近更新 更多