【问题标题】:Regular expression - get multiple matches into each group正则表达式 - 在每个组中获取多个匹配项
【发布时间】:2016-03-12 12:15:36
【问题描述】:

我有一个这样的字符串: raw_string = "(a=1)(b=2)(c=3)"

我想匹配这个并在每组括号中获取值,并在一个组中获取每个结果。 例如:

组 0 = "a=1"

组 1 = "b=2" 等等..

我试过/(\(.*\))/g,但它似乎不起作用。有人可以帮我解决这个问题吗?

谢谢!

【问题讨论】:

  • 你是如何应用正则表达式的?通过快速搜索,您似乎应该使用string.scan(/regex/)。此外,您可能不想要.*,因为它很贪心,可能会吃掉您的所有输入。我会将其更改为.*?,或者更好的是[^)]+(匹配任何不是结束括号的字符)。
  • 我想你只需要s.scan(/\(([^()]+)\)/)this code 满足您的需求吗?
  • 我们需要更好地描述您的尝试:向我们展示演示问题的最少代码。 Stack Overflow 不是“给我代码”网站,它是我们帮助您修复代码的地方。我们希望您已经尝试过,遇到过问题,再次尝试过,遇到过另一个问题,并且一旦您用尽了您的选择,然后再询问。见meta.stackoverflow.com/questions/261592/…How to Ask
  • 投反对票可能是因为你说你有一个字符串(a=1)(b=2)(c=3),但没有引号,这不是一个字符串,也不是任何Ruby对象。您可能认为这是在狡辩,但您应该包含引号还有另一个原因。您还应该将字符串分配给一个变量(例如,str = "(a=1)(b=2)(c=3)",以便读者可以在 cmets 和答案中使用该变量而无需定义它(并且您不能编写 str = (a=1)(b=2)(c=3))。最后,为什么不总是使用 valid示例中的 Ruby 对象?

标签: ruby regex pattern-matching regex-greedy


【解决方案1】:
str = "(a=1)(b=2)  (c=3)"

正如@stribizhev 在评论中所建议的那样:

r = /
    \(       # Match a left paren
    ([^\)]+) # Match >= 1 characters other than a right paren in capture group 1
    \)       # Match a right paren
    /x       # extended/free-spacing regex definition mode

str.scan(r).flatten
  #=> ["a=1", "b=2", "c=3"] 

注意([^\)]+) 可以替换为(.+?),使其成为任何字符的惰性匹配,就像我在这个替代正则表达式中所做的那样,它使用环视而不是捕获组:

r = /
    (?<=\()  # Match a left paren in a positive lookbehind
    .+?      # Match >= 1 characters lazily
    (?=\))   # Match a right paren in a positive lookahead
    /x

这里的lookbehind 可以替换为\(\K,其内容为“匹配左括号,然后忘记到目前为止匹配的所有内容”。

最后,你可以在右边使用String#split,然后用空格分隔,然后删除第一个左括号和最后一个右括号:

str.split(/\)\s*\(/).map { |s| s.delete '()' }
  #=> ["a=1", "b=2", "c=3"] 

如果我们可以写s.strip(/[()]/)不是很好吗?

【讨论】:

  • ...@stribizhev 在评论中这样做了,但由于他似乎没有提供答案...(您认为评论中只能引用一个用户?)
  • 我忙着带孩子,现在他们都去睡觉了:)
  • s.strip(/[()]/) 可以通过s.tr('()', '') 轻松完成。
  • @theTinMan。如您所知,strip 不接受争论。我经常希望它这样做,一个字符串或一个正则表达式。例如,假设我想从字符串的开头和结尾去除元音。我希望能够写str.strip(/[aeiou]+/)。我知道我可以使用gsub 和正则表达式来做到这一点,但我必须包括锚点和“or”。 strip 没有这样设计可能是有充分理由的,但我不知道那会是什么。
【解决方案2】:

如果您的意思是带括号的模式恰好出现 3 次(或不同的固定次数),那么这是可能的,但如果您希望该模式出现任意次数,那么 您可以' t一个正则表达式只能有固定数量的捕获或命名捕获。

【讨论】:

    【解决方案3】:

    只是为了表明您可以将它们放入任意数量的捕获组中:

    "(a=1)(b=2)(c=3)"[/#{'(?:\((.*?)\))?' * 99}/]
    [$1, $2, $3]
    #=> ["a=1", "b=2", "c=3"]
    

    【讨论】:

    • 这不是任意的。它固定为 99。无论您将该数字设置为多大,您都无法确定(除了机器限制之外)生成的正则表达式是否有足够的匹配项来匹配所有出现的模式,直到您使用正则表达式。
    • 当然可以,str.length 怎么样?
    • 好吧,这就是吹毛求疵。为了更准确地表达我的话:除非您事先以某种方式检查字符串,否则您无法确定,这会破坏/减少使用正则表达式匹配模式的目的。
    猜你喜欢
    • 2015-03-10
    • 2017-06-26
    • 2010-11-21
    • 2012-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-02
    • 2020-04-11
    相关资源
    最近更新 更多