目标
我正在尝试制作一个RegEx,它将解析出各种syslog条目中的特定数据,这些条目包含日志内容中的细微差别。虽然我可以使用多个RegEx语句来实现我的目标,但如果可能的话,我希望将这些语句组合到一个统一的RegEx中。
日志条目
我遇到的主要问题是,一些日志条目具有需要解析到命名组的URL,而其他日志条目没有任何URL。下面提供了这两个不同日志条目的示例。
包含URL的条目
Nov 3 11:33:04 host1 postfix/smtpd[12812]: NOQUEUE: reject: RCPT from 178.red-83-59-180.dynamicip.rima-tde.net[83.59.180.178]: 554 5.7.1 Service unavailable; Client host [83.59.180.178] blocked using b.barracudacentral.org; http://www.barracudanetworks.com/reputation/?pr=1&ip=83.59.180.178; from=<lmclapp68@newmail.spamcop.net> to=<user1@example.com> proto=ESMTP helo=<178.red-83-59-180.dynamicip.rima-tde.net>不带URL的条目
Nov 2 16:01:25 host1 postfix/smtpd[31667]: NOQUEUE: reject_warning: RCPT from mail1.sendersrv.com[185.3.229.125]: 554 5.7.1 Service unavailable; Client host [185.3.229.125] blocked using bl.spamcop.net; from=<bounces+rL59wUXq98_inBrG@sendersrv.com> to=<user1@example.com> proto=ESMTP helo=<mail1.sendersrv.com>RegEx语句
在随后的RegEx语句中,前两个是我当前用于前面的每条日志消息的语句。第三个RegEx是我尝试将这两者合并到一个RegEx中,它将解析来自任何一条日志消息的数据。我的尝试是使用一个条件语句,该语句基本上会检查http(s)是否存在,如果找到,则将其解析为指定的组。如果没有找到http(s),那么它将解析出直到下一个RegEx令牌为止的所有内容。
问题是,当我针对具有URL的日志条目测试RegEx时,RegEx似乎找不到http(s),尽管此标记被设置为可选(即使用?限定符)。但是,如果我删除?限定符,它确实会找到http(s),然后根据需要解析该URL。但是,如果没有限定符,RegEx将无法处理没有URL的日志条目。
使用URL解析条目
^(?P<datetime>.+) host1 postfix.+RCPT from (?P<srcDns>.+)\[(?P<srcIp>[0-9\.]+)\]:.+blocked using (?P<blkList>.+);.+https?:\/{2}(?P<entryUrl>.+);\s.+\sto=\<(?P<destEm>.+)>.+$解析不带URL的条目
^(?P<datetime>.+) host1 postfix.+RCPT from (?P<srcDns>.+)\[(?P<srcIp>[0-9\.]+)\]:.+blocked using (?P<blkList>.+);\s.+\sto=\<(?P<destEm>.+)>.+$尝试整合RegEx
^(?P<datetime>.+) host1 postfix.+RCPT from (?P<srcDns>.+)\[(?P<srcIp>[0-9\.]+)\]:.+blocked using (?P<blkList>.+)(?<=[a-z]);.+(https?:\/{2})?(?(5)(?P<entryUrl>.+)|.+)to=\<(?P<destEm>.+)>.+$我确信问题在于我对条件语句和?量词是如何工作的误解。
发布于 2021-11-07 16:48:44
看看你的模式,to:的电子邮件地址在标签<和>之间,但由于问题中的格式,它们没有显示出来。
像.+这样的模式中的部分首先匹配到字符串的末尾,然后回溯并尝试匹配模式的其余部分。
您可以使模式更具性能,使您想要和了解的部分更具体。
对于日期时间,可以使用^(?P<datetime>[A-Z][a-z]{2}\s+\d{1,2}\s* \d{1,2}:\d{1,2}:\d{1,2})使模式匹配指定的格式,而不是
对于(?P<blkList>[^;]+)和
;之外的任何字符匹配的被取反的字符类
对于组(?P<destEm>[^<>\s]+),您可以排除匹配的标记。
要使组与url匹配,可以使用?使组可选,而不是使用条件
例如
^(?P<datetime>[A-Z][a-z]{2}\s+\d{1,2}\s* \d{1,2}:\d{1,2}:\d{1,2}) host1 postfix\b.*? RCPT from (?P<srcDns>.*?)\[(?P<srcIp>[0-9\.]+)\]:.*? blocked using (?P<blkList>[^;]+);(?:.+?https?:\/\/(?P<entryUrl>[^;]+);)?\s.*? to=[^<]*<(?P<destEm>[^<>\s]+)>请参阅regex demo。
发布于 2021-11-07 06:39:06
您是否尝试过在像regex101这样的页面上测试您的正则表达式
to=\<(?P<destEm>.+)>似乎与您的示例不匹配。您应该删除<>或将to替换为helo。注意,在blkList之后使用惰性量词,否则可能会捕获太多文本。
然后,您可以使用?使您的url成为可选的,并且它应该在这两种情况下都有效:
^(?P<datetime>.+) host1 postfix.+RCPT from (?P<srcDns>.+)\[(?P<srcIp>[0-9\.]+)\]:.+blocked using (?P<blkList>.+?);(.+https?:\/{2}(?P<entryUrl>.+);\s)?.+\sto=(?P<destEm>.+?)\s.*$发布于 2021-11-07 06:51:02
一种方法是将第一个正则表达式中的.+https?:\/{2}(?P<entryUrl>.+);替换为(?:.+https?:\/{2}(?P<entryUrl>.+);)?,其中?:表示它是一个非捕获组,末尾的?表示它是可选的。
但是,它仍然不能工作,因为.+是贪婪的,所以改用惰性.+?。
最终正则表达式:
^(?P<datetime>.+?) host1 postfix.+?RCPT from (?P<srcDns>.+?)\[(?P<srcIp>[0-9\.]+)\]:.+?blocked using (?P<blkList>.+?);(?:.+?https?:\/{2}(?P<entryUrl>.+?);)?\s.+?\sto=\<(?P<destEm>.+?)>.+?$https://regex101.com/r/QkmXWz (查看实际操作)
https://stackoverflow.com/questions/69868994
复制相似问题