如何使这个正则表达式更紧凑?

时间:2008-11-15 22:14:27

标签: regex

假设我有一行像这样的文字

Small   0.0..20.0   0.00    1.49    25.71   41.05   12.31   0.00    80.56

我想捕获最后六个数字并忽略 Small 和前两组数字。

对于本练习,让我们忽略这样一个事实:只做一些字符串拆分而不是正则表达式可能更容易。

我有这个正则表达式,但有点可怕看

^(Small).*?[0-9.]+.*?[0-9.]+.*?([0-9.]+).*?([0-9.]+).*?([0-9.]+).*?([0-9.]+).*?([0-9.]+).*?([0-9.]+)

有没有办法压缩它?

例如,是否可以将对最后6个数字的检查合并为一个仍然将结果存储为6个单独的组匹配的语句?

3 个答案:

答案 0 :(得分:5)

如果你想让每个比赛保持在一个单独的反向引用中,你别无选择,只能“拼写出来” - 如果你使用重复,你可以将“所有六个组别”作为一个“或者只记录最后一个”,具体取决于在哪里放置捕获括号。所以不,不可能压缩正则表达式并且仍然保留所有六个单独的匹配。

一个更有效(虽然不漂亮)的正则表达式将是:

^Small\s+[0-9.]+\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+([0-9.]+)\s+([0-9.]+)\s+([0-9.]+)\s+([0-9.]+)

因为它明确地匹配空格。你的正则表达式将导致大量的回溯。我的正则表达式分为28个步骤,你的是106个。

暂且不谈:在Python中,你可以简单地做一个

>>> pieces = "Small   0.0..20.0   0.00    1.49    25.71   41.05   12.31   0.00    80.56".split()[-6:]
>>> print pieces
['1.49', '25.71', '41.05', '12.31', '0.00', '80.56']

答案 1 :(得分:3)

这是我能得到的最短时间:

^Small\s+(?:[\d.]+\s+){2}([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s*$

必须很长,因为必须明确指定每个捕获。不过,不需要捕捉“小”。但最好是具体(\ s而不是。),当你可以,并在两端锚定。

答案 2 :(得分:1)

为了实用性,您应该使用字符串替换来从复合部件构建正则表达式。

$d = "[0-9.]+"; 
$s = ".*?"; 

$re = "^(Small)$s$d$s$d$s($d)$s($d)$s($d)$s($d)$s($d)$s($d)";

至少那时你可以看到过去模式的结构,而改变一个部分会改变它们。

如果你想获得真正的ANSI,你可以短暂使用metasyntax并使其更容易阅读:

$re = "^(Small)_#D_#D_(#D)_(#D)_(#D)_(#D)_(#D)_(#D)"; 
$re = str_replace('#D','[0-9.]+',$re); 
$re = str_replace('_', '.*?' , $re ); 

(通过这种方式,它还可以轻松更改空间标记的定义,或者数字标记是什么)