什么样的正则表达式匹配这些输入?

What kind of regular expression matches these inputs?

我正在尝试解析来自测量机的数据。它输出以下形状的非结构化数据(制表符分隔):

# control.dat
X001  A3      100.0   20.0    40.0
      A5      124.0   
      I3      125.0 
X002  C3      200.054 20.494  45.0
      C5      122.0
      K3      122.01
        

是否建议使用正则表达式来查找以 X0... 开头的行,如果是,该怎么做?使用生成的解析数据,我想按以下形式填充 Python 字典(以便在需要时可以轻松转换为 JSON):

{ "PARSED" : [
    {
        "PARAM_1" : 100.0,
        "PARAM_2" : 20.0,
        "PARAM_3" : 40.0
    },
    {
        "PARAM_1" : 200.054,
        "PARAM_2" : 20.494
        "PARAM_3" : 45.0
    }
]}

目前我正在使用以下内容:

with("control.dat") as controls_data:
    controls = []
    for row in controls_data.split("\r\n"):
        #                   X          A3        100.0         20.0        40.0 
        tmp = re.findall(r"^X \d* \s* \D\d* \s* \d*\.\d* \s* \d*\.\d* \s* \d*.\d* \s*$", row)
        if len(tmp) > 0:
            controls.append(tmp[0])
    return controls_ra

是否真的需要对所有条目使用 forloop 运行 并将与模式匹配的行收集到单独的列表中?是否有可以立即应用于行列表的正则表达式?

任何建议都应与 Python 2.7.

兼容

一个选项是将所有行作为字符串加载,例如

file = open('control.dat',mode='r')
s = file.read()

然后使用groupdict()和命名捕获组

^X0\d+\s+\w+\s*(?P<PARAM_1>\d+(?:\.\d+)?)\s+(?P<PARAM_2>\d+(?:\.\d+)?)\s+(?P<PARAM_3>\d+(?:\.\d+)?)
  • ^ 字符串开头
  • X0\d+\s+\w+\s* 匹配 X0 1+ 和 1+ 个单词字符 (您可以使用 [A-Z]\d+ 使其更具体)
  • (?P<PARAM_1>\d+(?:\.\d+)?)\s+ 命名组 PARAM_1 匹配 1+ 位数字和可选的小数部分
  • (?P<PARAM_2>\d+(?:\.\d+)?)\s+ 命名组 PARAM_2 匹配 1+ 位数字和可选的小数部分
  • (?P<PARAM_3>\d+(?:\.\d+)?) 命名组 PARAM_3 匹配 1+ 位数字和可选的小数部分

Regex demo | Python 2 demo

s = ("X001  A3      100.0   20.0    40.0\n"
            "      A5      124.0   \n"
            "      I3      125.0 \n"
            "X002  C3      200.054 20.494  45.0\n"
            "      C5      122.0\n"
            "      K3      122.01\n"
            "        \n")

pattern = r"^X0\d+\s+\w+\s*(?P<PARAM_1>\d+(?:\.\d+)?)\s+(?P<PARAM_2>\d+(?:\.\d+)?)\s+(?P<PARAM_3>\d+(?:\.\d+)?)"
r = re.compile(r"^X0\d+\s+\w+\s*(?P<PARAM_1>\d+(?:\.\d+)?)\s+(?P<PARAM_2>\d+(?:\.\d+)?)\s+(?P<PARAM_3>\d+(?:\.\d+)?)", re.MULTILINE)
dict = {'PARSED': [m.groupdict() for m in r.finditer(s)]}

print(dict)

输出

{'PARSED': [{'PARAM_1': '100.0', 'PARAM_2': '20.0', 'PARAM_3': '40.0'}, {'PARAM_1': '200.054', 'PARAM_2': '20.494', 'PARAM_3': '45.0'}]}

如果你想每行循环,你可以使用 re.match 并检查 if tmp: 有一个结果,因为你不必使用拆分,因为该行已经有数据当前行。

例子

with open("control.dat", "r") as controls_data:
    controls = []
    dict = {}
    dict.setdefault('PARSED', [])
    for row in controls_data:
        tmp = re.match(r"^X0\d+\s+\w+\s*(?P<PARAM_1>\d+(?:\.\d+)?)\s+(?P<PARAM_2>\d+(?:\.\d+)?)\s+(?P<PARAM_3>\d+(?:\.\d+)?)", row)
        if tmp:
            dict['PARSED'].append(tmp.groupdict())
    print(dict)

输出

{'PARSED': [{'PARAM_1': '100.0', 'PARAM_2': '20.0', 'PARAM_3': '40.0'}, {'PARAM_1': '200.054', 'PARAM_2': '20.494', 'PARAM_3': '45.0'}]}