Python正则表达式在信息提取中的应用示例


   AI摘要:

这篇博客介绍了如何使用 Python 的正则表达式从日志中提取各种信息,包括时间戳、机器人名称列表、坐标点等。通过多个示例,展示了如何使用正则表达式匹配特定格式的数据,如日期时间、浮动数值、列表等,并结合 Python 内置的函数(如 eval()re.search())进行解析和处理。博客强调了正则表达式在日志数据提取中的实用性,帮助开发者快速从复杂的文本中提取所需的信息。


   示例1 —— 提取时间戳

[INFO] [1744205701.805933, 388.642000]: [2025-04-09 21:35:01] [log] This iteration begins

从如上所示的一行内容(line)中提取格式为 YYYY-MM-DD HH:MM:SS 的时间戳(不包括方括号),时间戳中的年份、月份、日期、小时、分钟和秒都由数字组成,并且这些数字由特定的分隔符(-:)分隔,可以使用如下所示例的正则表达式

time_str = re.search(r"\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]", line).group(1)

下面对正则表达式的逐部分进行分析:

   正则表达式:r"\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]"
  1. \[

    • 反斜杠 \ 用于转义字符 [, 因为在正则表达式中,[ 是一个元字符,表示字符类的开始。所以 \[ 表示匹配字面上的左中括号 [
  2. (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})

    • ():表示捕获组,即在匹配过程中将匹配到的内容分组存储,可以通过 .group(1) 来提取这个分组的内容。
    • \d{4}:表示匹配 4 个数字(即年份部分)。\d 匹配一个数字,{4} 表示数字的数量为 4。
    • -:表示字面上的连字符 -,用来分隔年、月、日。
    • \d{2}:表示匹配 2 个数字,用于匹配月、日、小时、分钟和秒。
    • ::表示字面上的冒号 :, 用来分隔小时、分钟和秒。
    • 该部分整体表示匹配日期时间的格式:YYYY-MM-DD HH:MM:SS
  3. \]

    • 反斜杠 \ 用于转义字符 ],因为在正则表达式中,] 是字符类的结束标志。所以 \] 表示字面上的右中括号 ]

   re.search() 方法:
  • re.search(r"\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]", line)
    • re.search() 是 Python 正则表达式模块 re 中的一个函数,用于在指定的字符串 line 中查找与给定模式匹配的第一个位置。
    • 它返回一个匹配对象(如果匹配成功),否则返回 None
    • 在这个例子中,r"\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]" 是匹配模式,它会查找一个形如 [YYYY-MM-DD HH:MM:SS] 的时间戳。
   .group(1) 方法:
  • .group(1) 表示提取第一个捕获组的内容,即 (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) 中匹配到的时间字符串。
    • 由于正则表达式中有一个捕获组(()),因此 .group(1) 会返回匹配到的日期时间部分,不包括外部的方括号。

所以,上述正则表达式可以从一行日志中提取出一个格式为 YYYY-MM-DD HH:MM:SS 的时间戳(不包括方括号)。



   示例2 —— 提取字符串列表

[WARN] [1744206318.523503, 467.530000]: [2025-04-09 21:45:18] [log] available robots: ['tb3_1', 'tb3_2']

从如上所示的一行内容(line)中提取出数量不确定的机器人名字列表,并存储到 current_group[“available_robots”]中,可以使用如下所示例的正则表达式

robots = re.search(r"\[(.*?)\]", line.split(":")[-1])
if robots:
    current_group["available_robots"] = eval(robots.group(0))

下面对正则表达式的逐部分进行分析:

   1. line.split(":")[-1]:
  • line.split(":"):将 line 按照冒号 : 分割成一个列表,分割的依据是 : 字符。这个操作将日志行从 : 分隔成多个部分。
  • [-1]:这个表示取列表中的最后一部分,通常是日志行中冒号 : 后面的内容。
   2. re.search(r"\[(.*?)\]", line.split(":")[-1]):
  • 这是一个正则表达式匹配操作,它用于在上一步提取的字符串(line.split(":")[-1])中查找机器人列表。

  • 正则表达式 r"\[(.*?)\]" 的含义:

    • \[:匹配字面上的左方括号 [,因为方括号是正则表达式中的特殊字符,需要使用反斜杠转义。
    • (.*?):这是一个捕获组,.*? 是一个非贪婪匹配,表示匹配任何字符,直到遇到右方括号 ]。非贪婪意味着它会尽可能少地匹配字符,以便尽早匹配到右方括号。
    • \]:匹配字面上的右方括号 ]
  • re.search() 会返回一个匹配对象,如果在提取的字符串中找到符合 [...] 格式的部分,就会将该部分提取出来。如果没有找到,返回 None

   3. robots.group(0):
  • .group(0)re.search() 返回的匹配对象的方法,它返回匹配到的整个字符串。由于正则表达式是用来提取方括号包围的内容,因此 robots.group(0) 将会返回一个包含方括号的字符串,例如 "['tb3_1', 'tb3_2']"
   4. eval(robots.group(0)):
  • eval() 是一个 Python 内置函数,它将字符串作为 Python 表达式进行求值。
    • 在这个例子中,eval(robots.group(0)) 会将字符串 "['tb3_1', 'tb3_2']" 解析成一个实际的 Python 列表 ['tb3_1', 'tb3_2']
    • 这意味着原始日志中的字符串 ['tb3_1', 'tb3_2'] 被转换为一个 Python 列表,可以直接操作。
   5. current_group["available_robots"] = eval(robots.group(0)):
  • 这一行将解析出来的机器人列表赋值给 current_group["available_robots"]
   6、安全性注意:

使用 eval() 时需要小心,因为它会执行字符串中的任何 Python 表达式。如果输入的字符串不受信任(例如来自用户的输入),它可能会导致安全漏洞。在这个特定场景下,如果 line 来自可靠的日志文件,那么使用 eval() 是可以接受的,但在处理外部输入时应该避免使用。



   示例3 —— 提取坐标点,并将它们转换为浮点数的列表

[INFO] [1744206321.989578, 467.911000]: [2025-04-09 21:45:21] [log] centroid record: ['[-3.0867193932760326, -2.0956288642773826]', '[-4.219862393320849, 3.255906439231088]', ...]

从如上所示的一行内容(line)中提取出数量不确定的二维位置坐标,并将它们转换为浮点数的列表,存储到 current_group[“centroids”]中,可以使用如下所示例的正则表达式

current_group["centroids"] = [list(map(float, p.strip("[]").split(','))) 
                           for p in eval(line.split(": ")[-1])]

以下是详细解释:

   1. line.split(": ")[-1]:
  • 这段代码首先用 split(": ")line 分割成多个部分,分割的依据是 : (冒号后面有一个空格)。
  • [-1] 表示取分割后的最后一个部分,这通常是一个包含坐标列表的字符串,例如:
    ['[-3.0867193932760326, -2.0956288642773826]', '[-4.219862393320849, 3.255906439231088]', ...]
    
   2. eval(line.split(": ")[-1]):
  • eval() 函数会将字符串中的表达式求值。在这个例子中,line.split(": ")[-1] 的值是一个字符串表示的列表(例如,['[-3.0867193932760326, -2.0956288642773826]', ...])。
  • eval() 会将其转换成 Python 对象,也就是一个列表,其中每个元素都是一个字符串表示的坐标对。例如:
    ['[-3.0867193932760326, -2.0956288642773826]', ...]
    
   3. list(map(float, p.strip("[]").split(','))):
  • 这部分代码用于将每个坐标字符串转换为一个浮点数列表。
    • p.strip("[]"):去掉每个坐标字符串两侧的方括号([]),例如将 [-3.0867193932760326, -2.0956288642773826] 转换为 -3.0867193932760326, -2.0956288642773826
    • split(','):用逗号分割字符串,得到一个包含两个数字的字符串列表,例如:['-3.0867193932760326', '-2.0956288642773826']
    • map(float, ...):将每个字符串转换为浮动数值。
    • list(...):将 map 对象转换为列表,得到坐标点 [ -3.0867193932760326, -2.0956288642773826 ]
   4. current_group["centroids"] = ...:
  • current_group["centroids"] 会被赋值为上述生成的坐标列表。
  • 这意味着 centroids 将是一个包含多个坐标点的列表,每个坐标点是一个浮动数值对。

   示例4 —— r’[,\s]+’

[,\s]:这是一个字符集,表示匹配逗号(,)或任何空白字符(\s)。[\s] 可以匹配空格、制表符、换行符等所有的空白字符。+:表示前面的字符集可以重复一次或多次。这意味着它会匹配连续的逗号或空白字符。所以,这个正则表达式 r’[,\s]+’ 匹配的是一个或多个逗号或者空白字符。

   示例5 —— 可能存在多处随机空格的坐标提取

[WARN] [1744205712.201956, 389.939000]: [2025-04-09 21:35:12] [log] Robot tb3_1 previous assigned point: [-2.37719159 -0.51813818], Info Gain: 2.1900000652670863

从如上所示的一行内容(line)中提取出可能存在多处随机空格的坐标,并存储到 coord_match中,可以使用如下所示例的正则表达式

coord_match = re.search(
    r"previous assigned point:\s*\["   # 匹配 "previous assigned point: [",包含可能的空格
    r"([-+]?\d*\.\d+|\d+)"  # 匹配 x 坐标
    r"\s*"  # 匹配空格
    r"([-+]?\d*\.\d+|\d+)"  # 匹配 y 坐标
    r"\s*\]", line  # 匹配 "]",并允许空格
)

这个正则表达式的目标是匹配日志行中 "previous assigned point:" 后面的坐标对 [-2.37719159 -0.51813818],并将其中的 x 和 y 坐标提取出来。

正则表达式分析:
  • previous assigned point:\s*\[

    • previous assigned point::匹配字面字符串 "previous assigned point:"
    • \s*:匹配零个或多个空格字符。
    • \[:匹配字面上的左方括号 [,因为方括号在正则表达式中是特殊字符,所以需要转义。
  • ([-+]?\d*\.\d+|\d+)

    • ([-+]?\d*\.\d+|\d+):这是一个捕获组,用来匹配数字(包括可能的正负号),可以是带小数点的数字(例如 -2.37719159),也可以是整数(例如 3)。具体而言:
      • [-+]?:匹配零个或一个正号 + 或负号 -
      • \d*\.\d+:匹配小数(例如 2.3-2.37719159),\d* 匹配零个或多个数字,\.\d+ 匹配小数点后至少一个数字。
      • |\d+:或者匹配整数。
  • \s*:匹配零个或多个空格字符,允许坐标之间有空格。

  • \]:匹配字面上的右方括号 ]

结果:

假设 line 是:

[WARN] [1744205712.201956, 389.939000]: [2025-04-09 21:35:12] [log] Robot tb3_1 previous assigned point: [-2.37719159 -0.51813818], Info Gain: 2.1900000652670863
  • 正则表达式会匹配到 "previous assigned point: [-2.37719159 -0.51813818]"
  • coord_match.group(1) 将提取到 -2.37719159(x 坐标),coord_match.group(2) 将提取到 -0.51813818(y 坐标)。

   示例6 —— 从字符串中提取出两个浮点数坐标

这段代码使用正则表达式从 pos_str 字符串中提取出两个浮点数坐标。具体来说,代码通过正则表达式匹配坐标对,并将两个浮点数(可能带有科学计数法)提取出来。

代码分析:

match = re.search(r"\[([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)[,\s]+([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)\]", pos_str)

正则表达式详细解析:

  1. \[\]:

    • \[\] 匹配字面上的方括号 [],因为方括号在正则表达式中是特殊字符,需要用反斜杠 \ 转义。
  2. ([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?):

    • 这部分是一个捕获组,用来匹配一个浮点数(包括整数、小数和科学计数法表示的数)。
    • [-+]?:匹配可选的正号 + 或负号 -,允许数值带有符号。
    • \d*:匹配零个或多个数字。这里是用来处理小数点前的数字(可以没有)。
    • \.?:匹配零个或一个小数点 .,用于处理整数和小数。
    • \d+:匹配一个或多个数字,用于处理小数点后的数字。
    • (?:[eE][-+]?\d+)?:这是一个非捕获组,匹配科学计数法部分,允许使用 eE 来表示指数部分,后跟一个可选的符号(+-)和一个或多个数字。例如,1.5e-32.0E+10
  3. [,\s]+:

    • [,\s]+ 匹配一个或多个逗号 , 或空白字符(包括空格、制表符等),这部分用于处理坐标之间的分隔符。
  4. ([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?):

    • 这是第二个捕获组,类似于第一个组,匹配第二个浮点数坐标。它的工作方式与第一个捕获组相同,处理第二个坐标值。

匹配逻辑:

  • pos_str:是待匹配的字符串,应该是一个包含两个浮点数坐标的字符串,格式类似于:

    "[ 0.24770621 -4.59249853 ]"
    

    或者

    "[1.23e4 -5.67E-2]"
    
  • 该正则表达式会提取这两个坐标(即,括号内的两个数字)。

示例:

假设 pos_str 为:

"[ 0.24770621 -4.59249853 ]"
  • 正则表达式会匹配到:
    • 第一个捕获组(x 坐标):0.24770621
    • 第二个捕获组(y 坐标):-4.59249853

提取值:

如果正则表达式成功匹配,match.group(1) 将包含第一个坐标值(x 坐标),match.group(2) 将包含第二个坐标值(y 坐标)。

示例代码:

pos_str = "[ 0.24770621 -4.59249853 ]"
match = re.search(r"\[([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)[,\s]+([-+]?\d*\.?\d+(?:[eE][-+]?\d+)?)\]", pos_str)

if match:
    x = match.group(1)
    y = match.group(2)
    print(f"x: {x}, y: {y}")
else:
    print("No match found.")

结果:

对于 pos_str = "[ 0.24770621 -4.59249853 ]",输出将是:

x: 0.24770621, y: -4.59249853

总结:

  • 正则表达式用于提取包含在方括号内的两个浮点数(可能带有科学计数法)的坐标。
  • 提取的坐标将被分别存储在 match.group(1)match.group(2) 中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕羽★

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值