使用正则表达式提取单词...如果存在

时间:2012-07-20 15:10:45

标签: regex parsing logging logparser

我想使用RE来解析日志文件并返回orderid(如果存在)。例如:

以下是示例日志

2012-07-19 12:05:04,288 [22] INFO  AddQueueCommand [(null)] - Status set to Subscribed
2012-07-19 12:05:04,288 [23] INFO  FooBarProviderFactory [(null)] - Missing Function : OrderId:102602 : Method:AddOrderToId : application:11
2012-07-19 12:05:04,288 [22] INFO  AddQueueCommand [(null)] - Status set to Pending
2012-07-19 12:05:04,288 [23] INFO  AddSubscription [(null)] - Subscription Added. OrderId:102603 : application:15
2012-07-19 12:05:04,288 [22] INFO  AddQueueCommand [(null)] - Status set to Subscribed

我想要做的是使用正则表达式,以便我可以解析日志消息的组件。但是当存在“OrderId”时,我希望能够解析orderid#。

这是我到目前为止所做的:

^
(?<before>.*)
(?<order>((?<=OrderId\:\s*)\d*))
(?<after>.*)
$

非常适合解析包含它们的行的orderid,但是当行没有它们时它会失败。我试过添加“?”零或一个到订单行然后解析所有行,但从不解析实际的orderid。它们总是空的。

希望有人能看出我做错了什么。谢谢!

(我希望它解析每一行,因为我要从每一行解析多个id值,它们可能存在也可能不存在。我希望它返回值,如果我搜索的是存在或null /空如果它不存在。它需要为每一行返回一些内容。这将插入到LogParser中,以便我们可以查询或记录特定的订单或其他变量)

3 个答案:

答案 0 :(得分:3)

如果您将<order>组设为可选,则<before>组将始终与整行匹配,因此匹配成功而不捕获OrderId,即使它在那里。在这种情况下,使其变得懒惰((?<before>.*?))会有所帮助(因为<after>组会匹配所有内容)。

但如果我理解正确的话,你可以在一个正则表达式中做你想做的所有事情。例如,假设您想要Status set to之后的单词(如果存在)每行OrderId:之后的数字(如果存在),那么您可以使用正则表达式

^
(?(?=.*Status\sset\sto\s)(?=.*Status\sset\sto\s(?<status>\w+))|)
(?(?=.*OrderId:)(?=.*OrderId:(?<order>\d+))|)
每行

并检查论坛<status>和/或<order>是否匹配。必要时展开。

这假设你的正则表达式引擎支持conditionals,这是.NET,Perl和PCRE的情况。

<强>解释

(?               # Conditional: IF it's possible to match...
 (?=.*OrderId:)  #  any string, followed by "OrderId:"
                 # THEN try to match this:
  (?=            #  Lookahead assertion:
   .*OrderId:    #   any string, followed by "OrderId:" 
   (?<order>\d+) #   followed by a number --> capture in group <status>
  )              #  End of lookahead
 |               # ELSE try to match this:
                 #  the empty string (always succeeds)
)                # End of conditional.

我们之所以需要两个前瞻:我们不希望正则表达式引擎实际消耗当前行中的任何字符,因为我们不知道条目将在哪个顺序,因此每个搜索都需要从行的开头开始。 (另一方面,如果条目的顺序总是固定的,那么正则表达式可以简化一点)。

答案 1 :(得分:0)

使用字符串扫描方法

如果您只想要OrderId记录编号,则可以通过扫描字符串以查找匹配的表达式来简化此任务。例如,假设您的日志数据存储在String log 中,在Ruby中您可以执行以下操作:

log.scan /OrderId:(\d+)/
=> [["102602"], ["102603"]]

仅存储匹配的文本。没有匹配的行不会存储数组值。

答案 2 :(得分:0)


您可以返回包含理解列表的ID列表:

 >>> import re
 >>> [ re.sub( r".*OrderId:(\d*).*", r"\1", line ) for line in logs.readlines() if 'OrderId' in line ]
 ['102602', '102603']