获取可变数量组的正则表达式
Regex that grabs variable number of groups
这不是问如何使用 re.findall()
或全局修饰符 (?g)
或 \g
的问题。这是在询问如何将 n
组与一个正则表达式匹配,其中 n
在 3 和 5 之间。
规则:
- 需要忽略第一个非space字符的行作为
#
(注释)
- 需要至少获得三个项目,始终按顺序:
ITEM1
、ITEM2
、ITEM3
class ITEM1(stuff)
model = ITEM2
fields = (ITEM3)
- 需要获取以下任何匹配项(如果它们存在)(未知顺序,并且可能会丢失)
write_once_fields = (ITEM4)
required_fields = (ITEM5)
- 需要知道哪个是哪个匹配项,因此要么按顺序检索匹配项,如果没有匹配项则返回
None
,或者检索对。
我的问题是这是否可行,如何实现?
我已经讲到这里了,但它还没有处理评论或未知顺序,或者是否缺少某些项目以及在您看到下一个 class
定义时停止搜索这个特定的正则表达式。 https://www.regex101.com/r/cG5nV9/8
(?s)\nclass\s(.*?)(?=\()
.*?
model\s=\s(.*?)\n
.*?
(?=fields.*?\((.*?)\))
.*?
(?=write_once_fields.*?\((.*?)\))
.*?
(?=required_fields.*?\((.*?)\))
我需要条件吗?
感谢您的任何提示。
我会这样做:
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.
这不是问如何使用 re.findall()
或全局修饰符 (?g)
或 \g
的问题。这是在询问如何将 n
组与一个正则表达式匹配,其中 n
在 3 和 5 之间。
规则:
- 需要忽略第一个非space字符的行作为
#
(注释) - 需要至少获得三个项目,始终按顺序:
ITEM1
、ITEM2
、ITEM3
class ITEM1(stuff)
model = ITEM2
fields = (ITEM3)
- 需要获取以下任何匹配项(如果它们存在)(未知顺序,并且可能会丢失)
write_once_fields = (ITEM4)
required_fields = (ITEM5)
- 需要知道哪个是哪个匹配项,因此要么按顺序检索匹配项,如果没有匹配项则返回
None
,或者检索对。
我的问题是这是否可行,如何实现?
我已经讲到这里了,但它还没有处理评论或未知顺序,或者是否缺少某些项目以及在您看到下一个 class
定义时停止搜索这个特定的正则表达式。 https://www.regex101.com/r/cG5nV9/8
(?s)\nclass\s(.*?)(?=\()
.*?
model\s=\s(.*?)\n
.*?
(?=fields.*?\((.*?)\))
.*?
(?=write_once_fields.*?\((.*?)\))
.*?
(?=required_fields.*?\((.*?)\))
我需要条件吗?
感谢您的任何提示。
我会这样做:
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.