如何修复我的正则表达式与贪婪的量词不匹配?

时间:2008-11-01 17:35:05

标签: regex perl parsing greedy regex-greedy

我有以下一行:

"14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)"

我使用一个简单的正则表达式来解析它:

if($line =~ /(\d+:\d+)\ssay;(.*);(.*);(.*);(.*)/) {
    my($ts, $hash, $pid, $handle, $quote) = ($1, $2, $3, $4, $5);
}

但是;最后搞砸了,我不知道为什么。贪婪的操作员不应该处理“一切”吗?

6 个答案:

答案 0 :(得分:18)

贪婪的算子试图抓住尽可能多的东西,仍然匹配字符串。发生的事情是第一个(在“说”之后)抓住“0ed673079715c343281355c2a1fde843; 2”,第二个采用“laka”,第三个发现“你好”,第四个匹配括号。

你需要做的是让除了最后一个之外的所有人都非贪婪,所以他们尽量少抓住并仍然匹配字符串:

(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*)

答案 1 :(得分:7)

(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*)

应该更好用

答案 2 :(得分:7)

虽然正则表达式很容易做到这一点,但我不确定这是最直接的方法。它可能是最短的,但实际上并不能使它成为最可维护的。

相反,我会建议这样的事情:

$x="14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)";

if (($ts,$rest) = $x =~ /(\d+:\d+)\s+(.*)/)
{
    my($command,$hash,$pid,$handle,$quote) = split /;/, $rest, 5;
    print join ",", map { "[$_]" } $ts,$command,$hash,$pid,$handle,$quote
}

这导致:

[14:48],[say],[0ed673079715c343281355c2a1fde843],[2],[laka],[hello ;)]

我认为这只是更具可读性。不仅如此,我认为它也更容易调试和维护,因为如果人类用笔和纸尝试同样的事情,这更接近于你将如何做到这一点。将字符串分解成块,然后您可以更轻松地解析 - 让计算机完全按照您的方式执行操作。当需要进行修改时,我认为这个会更好。 YMMV。

答案 3 :(得分:3)

尝试制作前3 (.*) ungreedy (.*?)

答案 4 :(得分:3)

如果以分号分隔的列表中的值本身不能包含任何分号,则只需将其拼写出来,即可获得最有效,最直接的正则表达式。如果某些值只能是,例如,一串十六进制字符,则将其拼写出来。当正则表达式与主题字符串不匹配时,使用懒惰或贪婪点的解决方案总会导致大量无用的回溯。

(\d+:\d+)\ssay;([a-f0-9]+);(\d+);(\w+);([^;\r\n]+)

答案 5 :(得分:2)

你可以通过附加问号来使*非贪婪:

$line =~ /(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*)/

或者你可以匹配除了最后一个部分之外的每个部分中除分号之外的所有内容:

$line =~ /(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*)/