【问题标题】:Regex Log Parsing - how to begin parsing lines at one event and stop parsing lines at another event?正则表达式日志解析 - 如何在一个事件中开始解析行并在另一个事件中停止解析行?
【发布时间】:2021-12-04 19:39:01
【问题描述】:

我有一个日志文件,每行跟踪多个游戏事件,但这也包括在“官方”游戏时间之外发生的事件(即赛前等)。我有预定义的正则表达式模式,可以读取和解析每个事件,并汇总这些统计数据,尽管这包括在正式回合之前和之后发生的多余统计数据。

我的统计数据聚合目前很好,我目前正在努力解析一系列两个事件。没有明确的“游戏开始”事件,但有一个“回合开始”事件,该事件对比赛期间开始的个回合都计数。游戏结束更简单,因为“游戏结束”是一个被记录的事件。

如果我能够读取“回合开始”事件和“游戏结束”事件,我将如何开始第一个实例中读取文件中的行 'round start',一旦触发游戏结束就读完台词?

eg:
line 37 | trigger "(Round_Start)"  <-- begin parsing here
...
line 192 | trigger "(Round_Start)"
...
line 304 | trigger "(Round_Start)"
...
line 486 | trigger "(Round_Start)"
...
line 594 | trigger "(Game_Over)"    <-- finish parsing here

查看下面的一些代码可能会有所帮助。

dmgEvent_P = re.compile(r'"([\w\s]+)<.*hurt "([\w\s]+)<.*\(dmg "(\d+)"')
hpEvent_P = re.compile(r'"([\w\s]+)<.*healed "([\w\s]+)<.*\(hp "(\d+)"')
roundStart_P = re.compile(r'trigger "(Round_Start)"')
gameOver_P = re.compile(r'trigger "(Game_Over)"')



matches = dmgEvent_P.finditer(contents)
    for match in matches:
        dealer = match.group(1)
        receiver = match.group(2)
        dmg = int(match.group(3))
        modifyDMG(dealer, receiver, dmg)
matches = healthEvent_P.finditer(contents)
    for match in matches:
        dealer = match.group(1)
        receiver = match.group(2)
        hp = int(match.group(3))
        modifyHP(dealer, receiver, hp)

还有其他正在跟踪的游戏内事件,但它们的功能非常相似。

就目前而言,我当前的代码目前通过完全按照每个正则表达式解析函数读取日志内容来解析所有事件,而不是逐行汇总。我希望能够在我上面定义的范围内共同解析这些行。

【问题讨论】:

  • 转义正则表达式中的文字括号。
  • 我使用括号来定义我从中提取数据的组。他们还必须在这种情况下逃脱吗?日志条目中没有括号。
  • 如果trigger "(Round_Start)"是您的文本,括号必须与模式中的\(\)匹配。
  • 我的短信是trigger "Round_Start"。我相信在这种情况下我应该没问题?

标签: python python-3.x regex


【解决方案1】:

你可以匹配trigger "(Round_Start)"并读取所有不包含trigger "(Game_Over)"的行

^.*?\btrigger "\(Round_Start\)".*(?:\n(?!.*\(Game_Over\)).*)*

Regex demo

如果 (Game_Over) 应该出现在行之后,您可以在捕获组中捕获它之前的行,然后匹配包含 (Game_Over) 的行

^(.*?\btrigger "\(Round_Start\)".*(?:\n(?!.*\(Game_Over\)).*)*)\n.*?\btrigger "\(Game_Over\)"

模式匹配

  • ^ 字符串开始
  • ( 捕获第 1 组
    • .*?\btrigger "\(Round_Start\)".*匹配包含触发器“(Round_Start)”的整行
    • (?:非捕获组作为一个整体重复部分
      • \n(?!.*\(Game_Over\)).* 匹配一个换行符,如果它不包含 (Game_Over) 则使用负前瞻匹配该行的其余部分。如果要排除更多行,可以使用(?!.*(?:\(Game_Over\)|another string)
    • )*关闭非捕获组并可选择重复
  • )关闭捕获组1
  • \n.*?\btrigger "\(Game_Over\)"匹配一个换行符,并在该行匹配触发器“(Game_Over)”

Regex demo

注意转义括号 \(\) 或 else"(Round_Start)" 将不匹配,并且只有 (Round_Start) 会在捕获组中捕获文本。

【讨论】:

  • 谢谢你!对不起,如果我误解了。那么这里的正则表达式所做的是捕获两个实例之间的所有行,然后我可以返回并发送以进行解析?
  • @crkn213 是的,该模式首先匹配trigger "(Round_Start),然后是该行的其余部分。然后它选择性地重复匹配所有不包含 (Game_Over) 的行,使用负前瞻 (?! 所以在这个正则表达式演示中,您可以看到捕获的部分以绿色突出显示 regex101.com/r/kKZO10/1
  • 我是否也能在同一行中捕捉到“游戏结束”的原因?语法如下trigger "Game_Over" reason "(Win Limit|TimeLimit)",其中有两个可能的游戏结束原因。我目前的正则表达式是(.*?\btrigger "\(Round_Start\)".*(?:\n.*)*)\n.*?\btrigger "\(Game_Over\)" reason \"(Win Limit|Time Limit)\"。此外,虽然当前提议的正则表达式不会在我的代码中返回匹配项,但删除 ^ 似乎已经解决了这个问题。
  • @crkn213 如果只有这两个允许的原因,那么您可以使用(Win Limit|TimeLimit) 捕获它们,并且您将拥有一个额外的捕获组。如果模式在省略^ 的情况下工作,那么也可以,只有匹配不会从字符串的开头开始。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-27
  • 1970-01-01
  • 1970-01-01
  • 2015-09-06
  • 2010-09-07
  • 1970-01-01
相关资源
最近更新 更多