用于查找标记 ID 的正则表达式

Regex for finding flagged IDs

假设您有一个包含以下内容的文本文件:

  X12              IK               888T
  G                I5J              P9
  544T             ZUK              ONI
 E6U5 Z339988      T8               N55
  886            W 9ZT              T95

每个元素都代表一个唯一 ID,长度可以是 1 到 4 个项目,其中每个项目可以是字符或数字,如上所示。单个元素由未知数量的 space 分隔。

现在到了棘手的部分:每个 ID 前面都会出现两个标志(E 和 W)。当为 ID 设置标志 F 时,ID 前面会有一个 E,后跟一个 space,然后是一个由单个字符和 6 个数字组成的错误代码。例如,对于错误代码为 Z339988 的示例中的 ID 6U5

也有可能是 ID 升起了标志 W。在这种情况下,标志将与 ID 本身用 space 分开,就像 ID 9ZT 一样。

为了以正确的方式处理每个 ID,我需要提取 3 个不同的列表,或者如果 ID 前面有两个标志之一,则至少需要不同。由于我是正则表达式的新手,所以我只能创建简单的查询,但不能创建带有条件或其他结构的查询。

所以来问我的问题:对于这个文件的单行,首先从该行中提取所有 ID 并在 ID 具有特定标志的情况下进一步区分的可能的正则表达式是什么? 如果由于性能原因可以仅使用一个正则表达式而不是在同一行上使用 3 个不同的正则表达式来完成,那就太好了

我的第一个解决方案是这样的,它找到单个 ID,但无法确定它是否标有特定标志:

[E|W\s](\S{1,4})\s

这个正则表达式可以吗?E\S{1,4}\s\S+|W\s\S{1,4}|\S{1,4}

This is a demo on regex101.

(?<flag>E|W\s)?(?<id>[a-z0-9]{1,4})(?<errorcode>\s[a-z0-9]{5,})?

应该完成你的任务。我假设错误代码是像 id 一样的字母数字。必须设置不区分大小写的全局标志,否则为 [a-zA-Z0-9].

  • (?<flag>E|W\s)? -> 可选标志,组名为 "flag"
  • (?<id>[a-z0-9]{1,4}) -> id,组名为 "id"
  • (?<errorcode>\s[a-z0-9]{5,})? -> 可选错误代码,组命名 "errorcode"

更多描述和示例请参阅 here

这用于查找带有 E 标志的 ID:

E\K\S+

Here Is Demo

这用于查找带有 W 标志的 ID:

W\s+\K\S+

Here Is Demo

您可以使用交替来匹配 3 种可能性中的任何一种,并使用 2 个捕获组来区分它们

\b(?<flagE>E[A-Z0-9]{1,4} [A-Z][0-9]{6})|(?<flagW>W [A-Z0-9]{1,4})|[A-Z0-9]{1,4}\b

说明

  • \b 字边界
  • (?<flagE> 命名组 flagE 匹配
    • E[A-Z0-9]{1,4} [A-Z]\d{6}匹配E,1-4次A-Z0-9,space,单[A-Z]和6位
  • ) 关闭群组
  • |
  • (?<flagW> 命名组 flagW
    • [A-Z0-9]{1,4}匹配A-Z0-9 1-4次
  • ) 关闭群组
  • |
  • [A-Z0-9]{1,4}匹配A-Z0-9 1-4次
  • \b 字边界

Regex demo

在同一行上获得多个组的另一种选择是利用 \G 断言上一场比赛结束时的位置:

(?:^(\d{4}-\d{1,2}-\d{1,2}T\d{1,2}:\d{1,2}:\d{1,2}Z)\h+|\G(?!^))(?:(?<flagE>(E)([A-Z0-9]{1,4}) ([A-Z][0-9]{6}))|(?<flagW>(W) ([A-Z0-9]{1,4}))|([A-Z0-9]{1,4}))(?:\h+|$)

Regex demo

使用命名捕获组和 if 子句仅在错误标志已上升时匹配错误代码:

(?<flag>(?<e_flag>E)|(?:(?<w_flag>W) ))?(?<id>[A-Z\d]{1,4})(?(e_flag) (?<error_code>[A-Z]\d{6}))

此正则表达式定义了以下组:

  1. 标志:EW␣ 或不存在
  2. e_flag:E 或不存在
  3. w_flag:W 或不存在
  4. id: id
  5. error_code: 错误代码或不存在

查看 regex101

上的演示

在某些方法中使用此正则表达式,例如 findAll,然后对于每个 mach,您可以提取 id 组。 如果您想测试 id 是否被标记,请检查 flag 组是否存在。 如果您想检查是否设置了特定标志,请检查 e_flagw_flag 组。 如果您对错误代码感兴趣,请提取 error_code 组。如果 e_flag 存在,则它始终存在,否则它将不匹配。

注意: 这是 'find'-Regex 而不是 'match'-Regex。它将跳过所有不符合规范的部分。

我宁愿选择更简单的正则表达式和一些编程逻辑(包括此处的 namedtuples):

from collections import namedtuple
import re

data = """
  X12              IK               888T
  G                I5J              P9
  544T             ZUK              ONI
 E6U5 Z339988      T8               N55
  886            W 9ZT              T95
"""

ID = namedtuple('ID', 'id flag errorcode')

def getIDs(data):
    def flag(id):
        if id[0] == 'E':
            parts = id.split(" ")
            return ID(id = parts[0][1:], flag = 'e', errorcode = parts[1])
        elif id[0] == 'W':
            parts = id.split(" ")
            return ID(id = parts[1], flag = 'w', errorcode = None)
        return ID(id = id, flag = None, errorcode = None)

    rx = re.compile(r'\s{2,}')
    ids = [[flag(id.strip()) for id in rx.split(line) if id]
           for line in data.split("\n") if line]
    return ids

ids = getIDs(data)
for id in ids:
    print(id)

这会产生

[ID(id='X12', flag=None, errorcode=None), ID(id='IK', flag=None, errorcode=None), ID(id='888T', flag=None, errorcode=None)]
[ID(id='G', flag=None, errorcode=None), ID(id='I5J', flag=None, errorcode=None), ID(id='P9', flag=None, errorcode=None)]
[ID(id='544T', flag=None, errorcode=None), ID(id='ZUK', flag=None, errorcode=None), ID(id='ONI', flag=None, errorcode=None)]
[ID(id='6U5', flag='e', errorcode='Z339988'), ID(id='T8', flag=None, errorcode=None), ID(id='N55', flag=None, errorcode=None)]
[ID(id='886', flag=None, errorcode=None), ID(id='9ZT', flag='w', errorcode=None), ID(id='T95', flag=None, errorcode=None)]