正则表达式可选匹配运算符:如何应用于字符串?

时间:2012-08-31 02:10:16

标签: python ruby regex perl

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

(1234).*?(abcd)?

到以下字符串:

1234567abcd

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

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

    这是怎么做到的?

    重申:

    (1234).*?(abcd)

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

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

    ====

    我认为这个问题需要进一步澄清。这是我想要做的更完整的例子,在ruby中。

    从我的日志文件中给出以下两个“doctored up”行:

    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]*)')
    

    显然在某些情况下会包含'views'文本,在其他行中,它不存在。

    我希望能够做到这样的事情:

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

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

5 个答案:

答案 0 :(得分:2)

您没有指定您想要的内容,至少不清楚,但我认为您需要以下内容:

  • 如果输入...1234567abcd...,则应匹配1234567abcd,并应捕获1234abcd
  • 如果输入...1234567abce...,则应匹配1234,应捕获1234

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

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

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

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

答案 1 :(得分:1)

锚定正则表达式:

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

答案 2 :(得分:1)

与ikegami相似,但我认为更简单:

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

答案 3 :(得分:0)

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

(1234).*?(abcd|)

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

答案 4 :(得分:0)

你应该分步进行。

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} // '--';
}