【问题标题】:What kind of regular expression matches these inputs?什么样的正则表达式匹配这些输入?
【发布时间】:2021-07-10 15:19:05
【问题描述】:

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

# 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 兼容。

【问题讨论】:

    标签: regex python-2.7


    【解决方案1】:

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

    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&lt;PARAM_1&gt;\d+(?:\.\d+)?)\s+ 命名组 PARAM_1 匹配 1+ 位和可选的小数部分
    • (?P&lt;PARAM_2&gt;\d+(?:\.\d+)?)\s+ 命名组 PARAM_2 匹配 1+ 位和可选的小数部分
    • (?P&lt;PARAM_3&gt;\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: 是否有结果,因为您不必使用 split,因为该行已经包含当前行的数据。

    例子

    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'}]}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 2013-04-19
      • 2018-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多