Ruby拆分字符串并保留分隔符

时间:2016-07-22 17:28:44

标签: ruby string symbols

在Ruby中,以下列方式分割字符串的最简单方法是什么?

  • 'abc+def'应拆分为['abc', '+', 'def']

  • 'abc\*def+eee'应拆分为['abc', '\*', 'def', '+', 'eee']

  • 'ab/cd*de+df'应拆分为['ab', '/', 'cd', '\*', 'de', '+', 'df']

我们的想法是将字符串拆分为这些符号:['-', '+', '*', '/']并将这些符号保存在适当位置的结果中。

2 个答案:

答案 0 :(得分:13)

选项1

/\b/word boundary,它的宽度为零,因此不会消耗任何字符

'abc+def'.split(/\b/)
# => ["abc", "+", "def"]

'abc*def+eee'.split(/\b/)
# => ["abc", "*", "def", "+", "eee"]

'ab/cd*de+df'.split(/\b/)
# => ["ab", "/", "cd", "*", "de", "+", "df"]

选项2

如果您的字符串包含其他字边界字符,而您只想在-+*/上进行拆分,那么您可以使用{{3 }}。如果使用捕获组,String#split还将在结果中包含捕获的字符串。 (感谢您指出这一点capture groups)(@Jordan抱歉,我在编辑时没有看到您的答案)

'abc+def'.split /([+*\/-])/
# => ["abc", "+", "def"]

'abc*def+eee'.split /([+*\/-])/
# => ["abc", "*", "def", "+", "eee"]

'ab/cd*de+df'.split /([+*\/-])/
# => ["ab", "/", "cd", "*", "de", "+", "df"]

选项3

最后,对于使用可能不支持使用捕获组进行字符串拆分的语言的用户,可以使用两个@Cary Swoveland。 Lookarounds也是零宽度匹配,因此它们不会消耗任何字符

'abc+def'.split /(?=[+*\/-])|(?<=[+*\/-])/
# => ["abc", "+", "def"]

'abc*def+eee'.split /(?=[+*\/-])|(?<=[+*\/-])/
# => ["abc", "*", "def", "+", "eee"]

'ab/cd*de+df'.split /(?=[+*\/-])|(?<=[+*\/-])/
# => ["ab", "/", "cd", "*", "de", "+", "df"]

这里的想法是拆分任何前面有一个分隔符的字符,或者其中一个分隔符后跟的任何字符。让我们做一点视觉

ab ⍿ / ⍿ cd ⍿ * ⍿ de ⍿ + ⍿ df

符号在其中一个分隔符之前或之后。所以这就是字符串被剪切的地方。

选项4

也许您的语言没有字符串split功能或合理的方式与正则表达式进行交互。很高兴知道你不必坐在那里猜测是否有巧妙的内置程序可以神奇地解决你的问题。几乎总有一种方法可以使用基本指令来解决您的问题

class String
  def head
    self[0]
  end
  def tail
    self[1..-1]
  end
  def reduce acc, &f
    if empty?
      acc
    else
      tail.reduce yield(acc, head), &f
    end
  end
  def separate chars
    res, acc = reduce [[], ''] do |(res, acc), char|
      if chars.include? char
        [res + [acc, char], '']
      else
        [res, acc + char]
      end
    end
    res + [acc]    
  end
end

'abc+def'.separate %w(- + / *)
# => ["abc", "+", "def"]

'abc*def+eee'.separate %w(- + / *)
# => ["abc", "*", "def", "+", "eee"]

'ab/cd*de+df'.separate %w(- + / *)
# => ["ab", "/", "cd", "*", "de", "+", "df"]

答案 1 :(得分:3)

我认为这与@ naomic的答案很接近,但是我会留下一点点差异。

splitters = ['-', '+', '*', '/']

r = /(#{ Regexp.union(splitters) })/ 
  # => /((?-mix:\-|\+|\*|\/))/

'abc+def'.split r
  #=> ["abc", "+", "def"] 
"abc\*def+eee".split r
  #=> ["abc", "*", "def", "+", "eee"] 
'ab/cd*de+df'.split r
  #=> ["ab", "/", "cd", "*", "de", "+", "df"] 

注意:

  • 正则表达式将#{ Regexp.union(splitters) }放在捕获组中,导致String#split包含执行拆分的字符串(第三段的最后一句)。
  • 第二个示例字符串必须是双引号才能转义*