【问题标题】:Regex optional match operator: how to apply to a string of characters?正则表达式可选匹配运算符:如何应用于字符串?
【发布时间】:2012-08-25 20:10:58
【问题描述】:

我在尝试应用以下正则表达式时遇到问题:

(1234).*?(abcd)?

到下面的字符串:

1234567abcd

我的期望是上面应该产生两个匹配:

  1. 1234
  2. abcd

但是,这不起作用。您可能会建议“好吧,只需删除尾随的? 字符?” -- 但我希望这第二种模式是可选的。

这是怎么做到的?

重申:

(1234).*?(abcd)

... 给出了想要的结果,但我搜索的字符串并不总是包含abcd

如果有人想知道,这是一个大图问题的简化示例。如果需要,我会解释的。

====

我认为这个问题需要进一步澄清。这是我在 ruby​​ 中尝试做的更完整的示例。

鉴于我的日志文件中的以下两行“篡改”:

Aug 28 00:00:05 app-system-1 app-prod[7660]: Completed 200 OK in 150ms (Views: 24.6ms | ActiveRecord: 66.1ms)
Aug 28 00:05:06 app-system-1 app-prod[10639]: Completed 302 Found in 81ms (ActiveRecord: 74.6ms)

我尝试在 ruby​​ 中编译一个正则表达式,如下所示:

d=Regexp.new('(?<timestamp>\w{1,3}\s\d{1,2}\s\d\d:\d\d:\d\d).*(?<in>in [0-9]*).*(?<views>Views: [0-9]*).*(?<activerecord>ActiveRecord: [0-9]*)')

显然,在某些情况下,“视图”文本将被包含在内,而在其他行中,则不存在。

我希望能够做类似的事情:

v=d.match(line)
if !v.nil?
    puts v[:timestamp]+ " " + v[:in] + " " + v[:views] + " " + v[:activerecord]

这显然是一个不完整的例子,但希望这可以澄清。

【问题讨论】:

    标签: python ruby regex perl


    【解决方案1】:

    你真的应该分步去做。

    if (my ($ts, $dur, $breakdown) = /
       ^
       (\w{3}[ ]\d{1,2}[ ]\d\d:\d\d:\d\d)
       .*?
       in[ ]([0-9]*)ms
       .*?
       \( ([^()]*) \)
    /xs) {
       my %breakdown = map /^([^:]+): (.*)ms/, split /\s*\|\s*/, $breakdown;
       say join ', ',
          $ts,
          $dur,
          $breakdown{Views} // '--',
          $breakdown{ActiveRecord} // '--';
    }
    

    【讨论】:

      【解决方案2】:

      类似于 ikegami 但我认为更简单:

      /(1234)(?:(?!abcd).)*(abcd)?/
      

      【讨论】:

        【解决方案3】:

        因为(a|) 大致相当于(a)? 我们可以使用:

        (1234).*?(abcd|)
        

        强制正则表达式引擎首先检查abcd。带有? 的可选规则的默认设置是假定它不存在(相当于(|abcd))。此默认行为对于确保正则表达式终止(更快)很重要。

        【讨论】:

        • 不,(a|) 实际上与(a)? 相同。它会在任何地方匹配,因为它总是什么都不匹配。
        • 呃,这不会改变任何事情。与(?:a|) 一样,a? 在尝试匹配 "" 之前尝试匹配 "a"
        • 在 perl 中,?喜欢匹配而不是不匹配,相当于{0,1}。 ??是首选不匹配的版本,相当于{0,1}?。如果在 python 或 ruby​​(标签中指示的其他语言)中不是这样,我很想听听。
        • @Alan Moore:在 perl 中,(a|)(a)? 的区别仅在于前者可以捕获 a 或空字符串,而后者可以捕获 a 或 undef。这是一个微妙的区别,但仍然是一个区别。
        • @ysth:我知道。我的意思是,就像你和 @ikegami 一样,?不是非贪婪的。 (这适用于 Python、Ruby 和我熟悉的所有其他风格,顺便说一句。PHP 具有 /U 修饰符,它使所有量词都是非贪婪的,但贪婪是默认值。)此外,贪婪或非贪婪是不相干;重要的是(a|)--就像(a)?--将匹配它应用的任何地方,因为它什么都不匹配。
        【解决方案4】:

        您没有具体说明您想要什么,至少没有明确说明,但我认为您想要以下内容:

        • 当给定...1234567abcd... 作为输入时,1234567abcd 应该匹配,1234abcd 应该被捕获。
        • 当给定...1234567abce... 作为输入时,1234 应该匹配,1234 应该被捕获。

        如果是这样,您可以使用:

        /(1234)(?:.*?(abcd))?/s
        

        我讨厌使用贪婪修饰符。它用于避免匹配某些序列,但不能保证它不会。我会改用以下内容:

        /
           (1234)
           (?:
              (?:(?!abcd).)*    # Safer than .*?
              (abcd)
           )?
        /sx
        

        【讨论】:

        • 我在原始问题陈述中对手头的“问题”添加了更多说明。我认为您可能正在帮助我解决这个问题。你能看看上面吗? :) 谢谢!
        • 您真的应该分步进行。 1) 提取括号,然后 2) 在“|”上拆分内容,然后 3) 从值中拆分键。
        【解决方案5】:

        锚定正则表达式有效:

        /(1234).*?(abcd)?$/
        

        【讨论】:

          猜你喜欢
          • 2015-07-31
          • 1970-01-01
          • 2011-04-29
          相关资源
          最近更新 更多