为什么使捕获组可选导致它永远不匹配?

时间:2013-02-11 05:31:15

标签: regex perl

我想我对正则表达式非常擅长,但是这个让我很难受。我正在尝试匹配国家气象服务预报公告中使用的某种语言。我在Windows上使用Perl 5.16。我还使用this online regex tester进行了测试。这是一个示例消息:

...A SEVERE THUNDERSTORM WARNING REMAINS IN EFFECT UNTIL 1130 PM CST FOR CENTRAL LAMAR COUNTY... AT 1106 PM CST...NATIONAL WEATHER SERVICE METEOROLOGISTS WERE TRACKING A SEVERE THUNDERSTORM CAPABLE OF PRODUCING PING PONG BALL SIZE HAIL...AND DESTRUCTIVE WINDS IN EXCESS OF 70 MPH. THIS STORM WAS LOCATED NEAR BAXTERVILLE MOVING EAST AT 50 MPH. THE SEVERE THUNDERSTORM WILL BE NEAR... PURVIS BY 1115 PM CST... WEST HATTIESBURG BY 1120 PM CST...

这是我的正则表达式:

/A SEVERE THUNDERSTORM.+?(?<hsize>QUARTER|GOLF BALL|PING PONG BALL|HALF DOLLAR)?.+?WINDS (?:IN EXCESS OF|OVER) (?<wmph>\d+) MPH.+WAS LOCATED (?:(?<dist>\d+) MILES (?<dir>\w+) OF|(?<near>NEAR)) (?<loc>[\w ]+).+MOVING (?<mdir>\w+) AT (?<mph>\d+) MPH/

问题是hsize参数始终返回空白。我希望它是可选的但是贪婪的,但它永远不会匹配。我试着把它变成非可选的:

/A SEVERE THUNDERSTORM.+?(?<hsize>QUARTER|GOLF BALL|PING PONG BALL|HALF DOLLAR).+?WINDS (?:IN EXCESS OF|OVER) (?<wmph>\d+) MPH.+WAS LOCATED (?:(?<dist>\d+) MILES (?<dir>\w+) OF|(?<near>NEAR)) (?<loc>[\w ]+).+MOVING (?<mdir>\w+) AT (?<mph>\d+) MPH/

哪个会导致它匹配,这对我来说毫无意义。正如你所看到的,我已经制作了通配符,所以我看不出发生了什么。

2 个答案:

答案 0 :(得分:5)

您可以更改正则表达式的一些内容,以强制引擎在尝试匹配任何内容之前搜索特殊文本。更改正则表达式的这一部分:

.+?(?<hsize>QUARTER|GOLF BALL|PING PONG BALL|HALF DOLLAR)?

要:

(?:.+?(?<hsize>QUARTER|GOLF BALL|PING PONG BALL|HALF DOLLAR)|.+?)

交替将强制引擎耗尽所有与特殊关键字匹配的可能性(第一种选择),然后继续匹配任何东西(第二种选择)。

答案 1 :(得分:4)

/A SEVERE THUNDERSTORM.+?(?<hsize>QUARTER|GOLF BALL|PING PONG BALL|HALF DOLLAR)?.+?WINDS/

我认为匹配是这样的:

  1. 找到"A SEVERE THUNDERSTORM"
  2. 先匹配.+?:第一次尝试使用空字符串。
  3. 匹配(?<hsize>...)?:从此位置开始,它只能匹配一个空字符串。
  4. 匹配第二个.+?:第一次尝试使用空字符串。
  5. 无法匹配"WINDS"。回到第4步。
  6. 多次回溯,最后第二个.+?匹配从THUNDERSTORM到下一个WINDS的整个字符串。
  7. 所以回溯永远不会回到第3步或第2步。

    也许您可以捕获THUNDERSTORMWINDS之间的所有文字,然后在其上运行单独的正则表达式,或将.+?中的一个或两个更改为与冰雹大小描述不匹配的内容