Perl正则表达式引用并不贪心

时间:2016-08-26 01:53:09

标签: regex perl regex-greedy

这是一个有效的正则表达式:

/(ANSI|AAMVA) (\d{6})(\d{2})(\d{2})(\d{0,2})((?:DL)|(?:ID))+(.*?)\g{-2}+([^"]+)/

这是一个示例字符串:

"@\n\nANSI 6334290212DL00389199ZO04420478DLDAQ3572928\nDAASMITH, JOHN DOE\nDAG\nDAL4389 NE 47TH AVE\nDAIASHLAND\nDAJOR\nDAK97555      \nDARC   \nDASD         \nDATM     \nDAU504\nDAW180\nDBA12201212\nDBB19780303\n"

我正在尝试匹配第二次可能在字符串中的分隔符DLID

我想匹配以前匹配的DLID中的任何一个。

问题是,如果我使用?来完成此任务,它就会停止贪婪并且更喜欢0匹配。

我很难过,我错过了?如何操作的基本内容?

编辑:问题是没有提取JSON数据,它正在解析msg位,使用JSON没有做任何事情来实现这一点。我将琴弦修剪成相关部分。

@hobbs的修复有效,因为它允许我将?更改为+并且仍然不匹配,如果没有任何内容。

作品! :)

/(ANSI|AAMVA) (\d{6})(\d{2})(\d{2})(\d{0,2})((?:DL)|(?:ID))+(.*?)(?:\g{-2}|(?="))+([^"]+)/

2 个答案:

答案 0 :(得分:3)

问题不在于\g{-2}?不贪婪,而是(.*?)之前的非贪婪,而\g{-2}?无法匹配,这意味着它不能失败。如果它不能失败,那么它不会强制它之前的组匹配超过0个字符。总是如此,(.*?)将不会匹配任何内容,\g{-2}将不匹配,([^"]+)将匹配所有内容。

我并不完全理解您要提取的格式(除了它的陈旧和奇怪,并让我想起CIBER帐单记录),但我建议你需要更多的锚定才能将正则表达式的注意力集中在正确的地方,或者您需要升级到类似格式的适当解析器。既然你说你添加?来处理分隔符永远不会出现的情况,那么最快的创可贴修复可能是(?:\g{-2}|(?=")),它断言你找到了分隔符,或者你没有找到它就得到了收尾报价。

虽然,鲍罗丁的观察也是有效的;首先解码JSON然后使用解码的JSON结构中的字符串,而不是尝试直接在JSON上运行正则表达式会好得多。在这种情况下,您应该寻找\z(字符串结尾)而不是"

答案 1 :(得分:0)

您的数据是JSON,尝试使用正则表达式模式处理它是非常错误的。有完美的Perl模块可以将文本转换为可导航的数据结构

我无法准确理解您的需求,因为您正在谈论DAID字符串,并且ID不会出现在示例数据中的任何位置。但这个简短的计划应该有所帮助

use strict;
use warnings 'all';
use feature 'say';

use JSON 'decode_json';

my $json = do {
    local $/;
    <DATA>;
};

my $data = decode_json $json;

say $data->{msg};


__DATA__
{"name":"SC","hostname":"tukwila","pid":11,"level":30,"msg":"@\n\nANSI 6334290212DL00389199ZO04420478DLDAQ3572928\nDAASMITH, JOHN DOE\nDAG\nDAL4389 NE 47TH AVE\nDAIASHLAND\nDAJOR\nDAK97555      \nDARC   \nDASD         \nDATM     \nDAU504\nDAW180\nDBA12201212\nDBB19780303\n","time":"2016-04-02T01:09:07.113Z","v":0}

输出

@

ANSI 6334290212DL00389199ZO04420478DLDAQ3572928
DAASMITH, JOHN DOE
DAG
DAL4389 NE 47TH AVE
DAIASHLAND
DAJOR
DAK97555      
DARC   
DASD         
DATM     
DAU504
DAW180
DBA12201212
DBB19780303