【问题标题】:Regex that grabs variable number of groups抓取可变数量组的正则表达式
【发布时间】:2023-04-01 05:41:01
【问题描述】:

这不是询问如何使用re.findall() 或全局修饰符(?g)\g 的问题。这是在询问如何将n 组与一个正则表达式匹配,n 在 3 和 5 之间。

规则:

  • 需要忽略第一个非空格字符为# (cmets) 的行
  • 需要至少获得三个项目,始终按顺序排列:ITEM1ITEM2ITEM3
    • class ITEM1(stuff)
    • model = ITEM2
    • fields = (ITEM3)
  • 需要获取以下任何匹配项(如果存在)(未知顺序,可能会丢失)
    • write_once_fields = (ITEM4)
    • required_fields = (ITEM5)
  • 需要知道哪个匹配是哪个,因此要么按顺序检索匹配,如果没有匹配则返回None,或者检索对。

我的问题是这是否可行,如何实现?

我已经做到了这一点,但它还没有处理 cmets 或未知订单,或者如果某些项目丢失,并且当您看到下一个 class 定义时停止搜索这个特定的正则表达式。 https://www.regex101.com/r/cG5nV9/8

(?s)\nclass\s(.*?)(?=\()
.*?
model\s=\s(.*?)\n
.*?
(?=fields.*?\((.*?)\))
.*?
(?=write_once_fields.*?\((.*?)\))
.*?
(?=required_fields.*?\((.*?)\))

我需要条件吗?

感谢您的任何提示。

【问题讨论】:

  • 这似乎不太适合正则表达式。您应该改为解析它。
  • @AdamSmith 有没有办法在没有正则表达式的情况下解析它?
  • AdamSmith 是对的,只需遍历文件中的行,如果它们以“#”开头,则跳过,然后选择一个函数来根据其第一个单词解析该行。您可以建立一个配对列表或其他任何东西,然后验证结果。

标签: python regex lookahead


【解决方案1】:

我会这样做:

from collections import defaultdict
import re

comment_line = re.compile(r"\s*#")
matches = defaultdict(dict)

with open('path/to/file.txt') as inf:
    d = {} # should catch and dispose of any matching lines
           # not related to a class
    for line in inf:
        if comment_line.match(line):
            continue # skip this line
        if line.startswith('class '):
            classname = line.split()[1]
            d = matches[classname]
        if line.startswith('model'):
            d['model'] = line.split('=')[1].strip()
        if line.startswith('fields'):
            d['fields'] = line.split('=')[1].strip()
        if line.startswith('write_once_fields'):
            d['write_once_fields'] = line.split('=')[1].strip()
        if line.startswith('required_fields'):
            d['required_fields'] = line.split('=')[1].strip()

您可以通过正则表达式匹配更轻松地做到这一点。

comment_line = re.compile(r"\s*#")
class_line = re.compile(r"class (?P<classname>)")
possible_keys = ["model", "fields", "write_once_fields", "required_fields"]
data_line = re.compile(r"\s*(?P<key>" + "|".join(possible_keys) +
                       r")\s+=\s+(?P<value>.*)")

with open( ...
    d = {} # default catcher as above
    for line in ...
       if comment_line.match(line):
           continue
       class_match = class_line.match(line)
       if class_match:
           d = matches[class_match.group('classname')]
           continue # there won't be more than one match per line
       data_match = data_line.match(line)
       if data_match:
           key,value = data_match.group('key'), data_match.group('value')
           d[key] = value

但这可能更难理解。 YMMV。

【讨论】:

    猜你喜欢
    • 2014-07-06
    • 1970-01-01
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    • 2013-08-21
    • 2014-12-30
    • 1970-01-01
    • 2014-01-27
    相关资源
    最近更新 更多