首页 > 解决方案 > 匹配两个lookbehinds之一

问题描述

我正在尝试通过从日志文件中Pandas.DataFrame提取设备来填充 a 中的列。id问题是它id前面可能有两个单独的模式,如下所示:

模式一:

(?<=cameraId=\')([a-z0-9-]+))

模式二:

(?<=/live/)([a-z0-9-]+)

注意:一条线不可能同时具有两种模式

问题是我使用该Pandas.String.str.findall()方法,并且我希望填充两种模式。

我可以成功实现预期的结果,如下面的代码所示:

import pandas as pd

line_1 = 'INFO:2021-04-19 00:25:10,647:instance_manager.py:MainProcess:1:got event notificationName=\'DETECTION_STARTED\' cameraId=\'ab1c-ab6c-a6f6-a6d6-ab666\' timestamp=\'2021-04-19T00:24:08.192169Z\''

line_2 = 'INFO:2021-04-19 00:25:11,278:instance_manager.py:MainProcess:1:An old record record for the stream rtsp://127.0.1.1:6666/live/a001-a00a-0016-a006-ab606.stream was successfully updated in the DB!'

df = pd.DataFrame(columns=['type', 'ts', 'process', 'subprocess', 'line', 'message'])

line_1_parsed = pd.Series([line_1]).str.extract(r'(?P<type>[^:]+):(?P<ts>.+,\d+):(?P<process>[^:]+):(?P<subprocess>[^:]+):(?P<line>[^:]+):(?P<message>[^$]+)')
line_2_parsed = pd.Series([line_2]).str.extract(r'(?P<type>[^:]+):(?P<ts>.+,\d+):(?P<process>[^:]+):(?P<subprocess>[^:]+):(?P<line>[^:]+):(?P<message>[^$]+)')

df =df.append(line_1_parsed, ignore_index=True)
df =df.append(line_2_parsed, ignore_index=True)

df.loc[:, 'cam_id'] = df.loc[:, 'message'].str.findall('(?<=cameraId=\')([a-z0-9-]+)|(?<=/live/)([a-z0-9-]+)')
df

,但它们以元组(模式 1,模式 2)的形式返回,如下所示Current Output

电流输出:

    type    ts  process     subprocess  line    message     cam_id
0   INFO    2021-04-19 00:25:10,647     instance_manager.py     MainProcess     1   got event notificationName='DETECTION_STARTED'...   [(ab1c-ab6c-a6f6-a6d6-ab666, )]
1   INFO    2021-04-19 00:25:11,278     instance_manager.py     MainProcess     1   An old record record for the stream rtsp://127...   [(, a001-a00a-0016-a006-ab606)]

我确实理解这是因为它尝试了两种模式并返回两者的匹配项,但我更希望它只包含成功的模式。

当然,我可以通过以下方式手动提取它:

df.loc[:, 'cam_id'] = df.loc[:, 'cam_id'].apply(lambda cam_id_tuple: cam_id_tuple[0][0] if cam_id_tuple[0][0] != '' else cam_id_tuple[0][1])
df

但它是一个相当麻烦的解决方案,而且不可扩展,以防我想添加模式。

期望的输出:

    type    ts  process     subprocess  line    message     cam_id
0   INFO    2021-04-19 00:25:10,647     instance_manager.py     MainProcess     1   got event notificationName='DETECTION_STARTED'...   [ab1c-ab6c-a6f6-a6d6-ab666]
1   INFO    2021-04-19 00:25:11,278     instance_manager.py     MainProcess     1   An old record record for the stream rtsp://127...   [a001-a00a-0016-a006-ab606]`

Nonte:cam_id列包含字符串而不是元组

提前致谢。

标签: python-3.xregexpandas

解决方案


我们可以使用str.extract具有单个捕获组的正则表达式模式

df['message'].str.extract(r'(?:cameraId=\'|/live/)([a-z0-9-]+)', expand=False)

0    ab1c-ab6c-a6f6-a6d6-ab666
1    a001-a00a-0016-a006-ab606
Name: message, dtype: object

正则表达式详细信息:

  • (?:cameraId=\'|/live/): 非捕获组
    • cameraId=\': 第一个选择匹配字符的cameraId='字面意思
    • /live/: 第二种选择匹配字符的/live/字面意思
  • ([a-z0-9-]+): 第一个捕获组
    • [a-z0-9-]+:匹配列表中存在的任何字符[a-z0-9-]一次或多次

见网上regex demo


推荐阅读