如何使用单行解析需要多个匹配的csv输出?

时间:2014-02-18 11:57:37

标签: regex linux perl

我有一个场景,我从DB中取出了后处理/过滤值。我正在使用perl ple来完成这项任务。一切正常,直到我遇到包含多个text标记的提取输出(csv)。请参阅示例here。如果只有一个文本标记,则代码的工作方式相同(正则提取正则表达式)。在我的数据库中有一些实例,其中有多个文本文件(即规则条件)。

代码是

echo "COPY (SELECT rule_data FROM custom_rule) TO STDOUT with CSV HEADER" | psql -U qradar -o /tmp/Rules.csv qradar;
perl -ple '
    ($enabled) = /(?<=enabled="").*?(?="")/g;
    ($group)   = /(?<=group="").*?(?="")/g;
    ($name)    = /(?<=<name>).*?(?=<\/name>)/g;
    ($text)    = /(?<=<text>).*?(?=<\/text>)/g;
    $_= "$enabled;$group;$name;$text";
    s/&lt;.*?&gt;//g;
' Rules.csv > rules_revised.csv

只需在示例输出上运行代码,我就会在rule_revised文件中获得以下内容。

  

true;流动性测试; DoS:局部洪水(其他);流动偏差时   是以下任何出境

实际上该行在出站之后被截断,其实际上应该包含与此类似的信息。

  

当使用相同的源IP看到至少3个流时,   目标IP在5分钟内,当IP协议是其中之一   以下IPSec,Uncommon以及源数据包大于   60000

已尝试通过使正则表达式贪婪地移除$ text中的?来解决此问题,但随后它会在text之间溢出,直到最后{{1}最后删除text会使其余部分混乱,因为它包含了我最初打算在进行正则表达式贪婪更改之前所包含的所有标记字符(即html)元素。

2 个答案:

答案 0 :(得分:1)

您是否尝试使用s修饰符,使点匹配换行:

perl -ple '
    ($enabled) = /(?<=enabled="").*?(?="")/g;
    ($group)   = /(?<=group="").*?(?="")/g;
    ($name)    = /(?<=<name>).*?(?=<\/name>)/g;
    ($text)    = /(?<=<text>).*?(?=<\/text>)/gs;
    #                                 here ___^
    $_= "$enabled;$group;$name;$text";
    s/&lt;.*?&gt;//g;
' Rules.csv > rules_revised.csv

答案 1 :(得分:1)

您获得多个匹配的截断结果的原因是您只存储第一个匹配。

($text)    = /(?<=<text>).*?(?=<\/text>)/g;

这只存储第一场比赛。如果将该标量更改为数组,则将捕获所有匹配项:

(@text)    = /(?<=<text>).*?(?=<\/text>)/g;

插入数组时,它会在元素之间插入空格($"的值)。如果您不想这样,可以将$"的值更改为可接受的分隔符。要清楚,您可以更改两个字符以获得以下行:

(@text)    = /(?<=<text>).*?(?=<\/text>)/g;
...
$_= "$enabled;$group;$name;@text";

如果我使用这些更改在您的示例上运行代码,则输出如下所示:

  

false;流属性测试; DoS:本地洪水(其他);当流量偏差是以下任何一个出站时,当使用相同的源IP看到至少3个流时,当IP协议为5分钟时,目标IP为以下IPSec之一,源数据包大于60000时不常见