Python 如何从预定义块构建正则表达式
我想基于模板和一组预定义块构建一个正则表达式,并使用string.template进行替换 例如:Python 如何从预定义块构建正则表达式,python,regex,Python,Regex,我想基于模板和一组预定义块构建一个正则表达式,并使用string.template进行替换 例如: 模板:/data/${year}{month}{day}/${year}{month}{day}{type}{id}.dat 区块: 日期:(?P\d{2}) 月份:(?P\d{2}) 年份:(?P\d{4}) 类型:(?P[BDPCLNIYSQJ]) id:(?P\d{8}) >字符串.模板(模板).safe\u替换(块) /数据/( 问题在于重复的名称组,这在正则表达式中是不被接受
- 模板:
/data/${year}{month}{day}/${year}{month}{day}{type}{id}.dat
- 区块:
- 日期:
(?P\d{2})
- 月份:
(?P\d{2})
- 年份:
(?P\d{4})
- 类型:
(?P[BDPCLNIYSQJ])
- id:
(?P\d{8})
- 日期:
>字符串.模板(模板).safe\u替换(块)
/数据/(
问题在于重复的名称组,这在正则表达式中是不被接受的
我正在寻找一种方法来纠正模板(在替换之前或之后),一种方法来欺骗re来吞下重复的模板,或者一种全新的方法来解决这个问题 去掉?p name元素。 即 我以前从未使用过?p功能
您的regexp模板想法很好 应用模板两次,一次设置名称,然后使用输出生成最终的regexp
day='(?P<$dayname>\d{2})'
d=dict(dayname='day_start')
Template(day).safe_substitute(d)
day='(?P\d{2})'
d=dict(dayname='day\u start')
模板(天)。安全替换(d)
重复所有需要的名称,然后将它们全部输入到最终模板中,该模板使用第1天第2天等我不确定Python,但PCRE和Perl都支持(?(定义)…)构造。所以你可以用这样的东西
(?x)
(?(定义)
(?(?&long_date);(?&short_date))
((((?&year)(?&month)(?&day)(?&type)(?&id))
(年、月、日)
(?\d{2})
(?\d{2})
(?\d{4})
(?[BDPCLNIYSQJ])
(?\d{8})
)
(?&日期)
我使用“x”修饰符(?x)只是为了使正则表达式更具可读性(现在正则表达式中的空白被忽略)
形式为(?(定义)…)的“条件组”可用于定义
从未内联计算但可以内联计算的组(命名和编号)
从别处被称为“子程序”。实际上,定义
条件总是错误的。在这种情况下,可能只有一种选择
小组
听从朋友的建议后,我找到了一种达到预期效果的方法 其思想是在替换regex块之前修改模板字符串以消除重复变量。事实上,它不是删除重复项,而是使用(?P=name)语法引用第一个来替换它们。通过这种方式,您可以强制使用该块的所有地方的内容都相同 我将假定regex组名与模板块名相同。这在问题示例中是不正确的,但是可以毫无问题地进行更改 要转换重复项,我使用以下函数:
>>> def remove_duplicate_blocks(template):
regex = '\$\{([\w]+)\}'
def alt_seen(matchobj):
x = matchobj.group(1)
if x not in seen and not seen_add(x): return '${%s}' % x
else: return '(?P=%s)' % x
seen = set()
seen_add = seen.add
return re.sub(regex, alt_seen, template)
它返回转换后的模板,没有重复项,并强制所有相似的块具有相同的内容
之后,只需更换积木
>>> unique_blocks_template = remove_duplicate_blocks(template)
>>> print unique_blocks_template
/data/${year}_${month}_${day}/(?P=year)(?P=month)(?P=day)_${type}_${id}.dat
>>> string.Template(unique_blocks_template).safe_substitute(blocks)
'/data/(?P<year>\\d{4})_(?P<month>\\d{2})_(?P<day>\\d{2})/(?P=year)(?P=month)(?P=day)_(?P<type>[BDPCLNIYSQJ])_(?P<id>\\d{8}).dat'
>>唯一\u块\u模板=删除\u重复\u块(模板)
>>>打印唯一的\u块\u模板
/数据/${year}{month}{day}/(?P=year)(?P=month)(?P=day){type}{id}.dat
>>>string.Template(唯一\u块\u模板).安全\u替换(块)
“/data/(?P\\d{4})(?P\\d{2})(?P\\d{2})/(?P=year)(?P=month)(?P=day)(?P[BDPCLNIYSQJ])(?P\\d{8}).dat”
问题中未提及,但同样的原始模板也可用于重建我们希望与正则表达式匹配的字符串,这是此代码的原始目标。您可以给它们不同的名称,否?其目的是能够在不更改块的情况下重用块?p元素被命名(如“(?p\d{2})”,因为我想按名称访问匹配的组。由于没有先验的分组,我需要使用这些名称来知道我得到了什么。好吧,然后应用模板两次,我会尝试这样做,因为这个注释框很难回答:)这似乎是一种正确的方法,但不幸的是python的re似乎不支持这种构造。如果我理解正确,这需要我为每个regex名称外观提供不同的名称,可以这么说。这样做的目的是不需要块以外的额外输入。
day='(?P<$dayname>\d{2})'
d=dict(dayname='day_start')
Template(day).safe_substitute(d)
(?x)
(?(DEFINE)
(?<date> (?&long_date) | (?&short_date))
(?<long_date> (?&year) _ (?&month) _ (?&day) _ (?&type) _ (?&id))
(?<short_date> (?&year) _ (?&month) _ (?&day))
(?<day> \d{2})
(?<month> \d{2})
(?<year> \d{4})
(?<type> [BDPCLNIYSQJ])
(?<id> \d{8})
)
(?&date)
>>> def remove_duplicate_blocks(template):
regex = '\$\{([\w]+)\}'
def alt_seen(matchobj):
x = matchobj.group(1)
if x not in seen and not seen_add(x): return '${%s}' % x
else: return '(?P=%s)' % x
seen = set()
seen_add = seen.add
return re.sub(regex, alt_seen, template)
>>> unique_blocks_template = remove_duplicate_blocks(template)
>>> print unique_blocks_template
/data/${year}_${month}_${day}/(?P=year)(?P=month)(?P=day)_${type}_${id}.dat
>>> string.Template(unique_blocks_template).safe_substitute(blocks)
'/data/(?P<year>\\d{4})_(?P<month>\\d{2})_(?P<day>\\d{2})/(?P=year)(?P=month)(?P=day)_(?P<type>[BDPCLNIYSQJ])_(?P<id>\\d{8}).dat'