使用管道联接正则表达式集时发生正则表达式模块错误



出于性能目的,我尝试使用管道将一组正则表达式转换为一个正则表达式。

self.regexes_token = [
{'descricao':'site www.', 'regex': r'^www.(.+?)$'},
{'descricao':'apenas pontuacao','regex':r'^[[:punct:]]+?$'},
{'descricao':'palavra com sinal negativo', 'regex': r'^(-)(.*?)$', 'grupo': r'2'},
{'descricao':'pronomes e títulos', 'regex': r'^(sra?|exm[º|°|o]|dr[a|ª]?|(v.)?ex.?(a|ª).?).??$'},
{'descricao':'oab sigla', 'regex': r'^oab/[a-z]{2}$'},
{'descricao':'termos irrelevantes', 'regex': r'^(s/n|e/ou|e-?mail|cep|rj|tel.?(/fax|efone)?|anos?|rua|cpf|www).?$'},
{'descricao':'chassi (VIN)', 'regex': r'^[A-Za-z0-9]{1}[A-Za-z]{2}[A-Za-z0-9]{9}[d+]{5}$'},
{'descricao':'data_br', 'regex': r'^(?:(?:31(/|-|.)(?:0?[13578]|1[02]))1|(?:(?:29|30)(/|-|.)(?:0?[1,3-9]|1[0-2])2))(?:(?:1[6-9]|[2-9]d)?d{2})$|^(?:29(/|-|.)0?23(?:(?:(?:1[6-9]|[2-9]d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))|(?:0?[1-9]|1d|2[0-8])(/|-|.)(?:(?:0?[1-9])|(?:1[0-2]))4(?:(?:1[6-9]|[2-9]d)?d{2})$'},
{'descricao':'um char e ponto', 'regex': r'^w[[:punct:]]$'},
{'descricao':'rg','regex': r'^d{2}.d{3}.d{3}-d(/.*)?'},
{'descricao':'unidades de medidas', 'regex': r'^(d{1,2},?x?)+(cm|m(l|²|2|m)?|k(g|m))$'},
{'descricao':'zero seguido de qualquer coisa', 'regex': r'^0(.*)$'},
{'descricao':'::punct:: seguido de qualquer coisa','regex':r'^[[:punct:]](.+?)$'},
{'descricao':'telefone avulso', 'regex': r'^d{4,5}-d{4}$'},
{'descricao':'ano', 'regex': r'b(19|20)d{2}.?b'},
{'descricao':'contém char especial', 'regex': r'^.*?(~|^|¿|¡|>|<|»|#|£|?|»|·|#|*|=|+|¥|€|||µ|®)+.*?$'}
]


self.regexes_token_union = r'('+'|'.join([d['regex'] for d in self.regexes_token])+r')'
print(self.regexes_token_union)

遵循正则表达式:

(^www.(.+?)$|^[[:punct:]]+?$|^(-)(.*?)$|^(sra?|exm[º|°|o]|dr[a|ª]?|(v.)?ex.?(a|ª).?).??$|^oab/[a-z]{2}$|^(s/n|e/ou|e-?mail|cep|rj|tel.?(/fax|efone)?|anos?|rua|cpf|www).?$|^[A-Za-z0-9]{1}[A-Za-z]{2}[A-Za-z0-9]{9}[d+]{5}$|^(?:(?:31(/|-|.)(?:0?[13578]|1[02]))1|(?:(?:29|30)(/|-|.)(?:0?[1,3-9]|1[0-2])2))(?:(?:1[6-9]|[2-9]d)?d{2})$|^(?:29(/|-|.)0?23(?:(?:(?:1[6-9]|[2-9]d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))|(?:0?[1-9]|1d|2[0-8])(/|-|.)(?:(?:0?[1-9])|(?:1[0-2]))4(?:(?:1[6-9]|[2-9]d)?d{2})$|^w[[:punct:]]$|^d{2}.d{3}.d{3}-d(/.*)?|^(d{1,2},?x?)+(cm|m(l|²|2|m)?|k(g|m))$|^0(.*)$|^[[:punct:]](.+?)$|^d{4,5}-d{4}$|b(19|20)d{2}.?b|^.*?(~|^|¿|¡|>|<|»|#|£|?|»|·|#|*|=|+|¥|€|||µ|®)+.*?$)

但当我尝试运行(编译(时,python的regex模块(不是重新(出现了一个错误:

regex._regex_core.error: cannot refer to an open group at position 272

我用记事本++看到了";col";位置,但即使在那时我也无法检测到这个是什么打开的组

";令人困惑的事情;当我在循环中运行每个正则表达式时,它运行得很好(但性能不好(

那么,我该怎么解决这个问题呢?

这里的基本错误是,当您将正则表达式与|组合时,组运算符2将不会引用试图引用它的表达式中的第二个组而是引用组合正则表达式中第二个带括号的组。

部分修复方法是在所有地方使用非分组括号,除非您确实需要引用回一个组。一个更好的解决方案是在需要的地方定义命名的组,这样您就可以按名称而不是按编号引用它们。

实际的错误消息是试图在中说

r'^(?:(?:31(/|-|.)(?:0?[13578]|1[02]))1...

不能使用1,因为以第一个左括号开头的组尚未定义,因为我们还没有看到它的右括号。总的来说,第一个组是从r'(' + '|'.join(...) + r')'开始的,所以你必须最低限度地重新编号,以匹配组合正则表达式的编号——但同样,这几乎是不可维护的,而且命名组很容易避免(至少在一定程度上;如果你有很多命名组,跟踪名称冲突等也会成为一个问题(。

可能您正试图引用捕获的日期分隔符?如果是,请尝试

r'^(?:(?:31(?P<sep>[-/.])(?:0?[13578]|1[02]))(?P=sep)...

其中我还通过使用字符类简化了捕获表达式。

切向而言,不需要反斜杠——斜杠根本不是regex元字符,所以它只是匹配自己。还要注意,在一个字符类中,您只有一个字符列表,因此这些字符不应该用|分隔(当然,如果您想匹配一个文本|,您可以包含一次|,但在您的示例中似乎不是这样(。

这里对您的定义进行了一次非常机械的重构,将所有分组括号替换为非分组括号,并将组替换为命名组,希望我能够正确猜测组应该匹配什么,同时纠正与斜杠和字符类相关的简单初学者错误。还有一个多余的{1}——很明显,一个字符的单个实例已经完全匹配了,你不必拼写出有一个。(还想知道[1,3-9]是否应该是[13-9]?(

self.regexes_token = [
{'descricao':'site www.', 'regex': r'^www.(?:.+?)$'},
{'descricao':'apenas pontuacao','regex':r'^[[:punct:]]+?$'},
{'descricao':'palavra com sinal negativo', 'regex': r'^(?:-)(?P<palavra>.*?)$', 'grupo': 'palavra'},
{'descricao':'pronomes e títulos', 'regex': r'^(?:sra?|exm[º°o]|dr[aª]?|(?:v.)?ex.?[aª].?).??$'},
{'descricao':'oab sigla', 'regex': r'^oab/[a-z]{2}$'},
{'descricao':'termos irrelevantes', 'regex': r'^(?:s/n|e/ou|e-?mail|cep|rj|tel.?(?:/fax|efone)?|anos?|rua|cpf|www).?$'},
{'descricao':'chassi (VIN)', 'regex': r'^[A-Za-z0-9][A-Za-z]{2}[A-Za-z0-9]{9}[d+]{5}$'},
{'descricao':'data_br', 'regex': r'(?:(?:31(?P<sep>/|-|.)(?:0?[13578]|1[02]))(?P=sep)|(?:(?:29|30)(?P<sep2>/|-|.)(?:0?[1,3-9]|1[0-2])(?P=sep2)))(?:(?:1[6-9]|[2-9]d)?d{2})$|^(?:29(?P<sep3>/|-|.)0?2(?P=sep3)(?:(?:(?:1[6-9]|[2-9]d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))|(?:0?[1-9]|1d|2[0-8])(?P<sep4>/|-|.)(?:(?:0?[1-9])|(?:1[0-2]))(?P=sep4)(?:(?:1[6-9]|[2-9]d)?d{2})$'},
{'descricao':'um char e ponto', 'regex': r'^w[[:punct:]]$'},
{'descricao':'rg','regex': r'^d{2}.d{3}.d{3}-d(?:/.*)?'},
{'descricao':'unidades de medidas', 'regex': r'^(?:d{1,2},?x?)+(?:cm|m[l²2m]?|k[gm])$'},
{'descricao':'zero seguido de qualquer coisa', 'regex': r'^0(?:.*)$'},
{'descricao':'::punct:: seguido de qualquer coisa','regex':r'^[[:punct:]](?:.+?)$'},
{'descricao':'telefone avulso', 'regex': r'^d{4,5}-d{4}$'},
{'descricao':'ano', 'regex': r'b(?:19|20)d{2}.?b'},
{'descricao':'contém char especial', 'regex': r'^.*?[~^|¿¡><»#£?»·*=+¥€\µ®]+.*?$'}
]
self.regexes_token_union = r'|'.join([d['regex'] for d in self.regexes_token])

实际上没有必要在并集表达式周围使用括号;他们什么都不加。

还请注意,在命名相应的组之后,我是如何用'grupo': 'palavra'替换'grupo': r'2'的——显然,您需要调整尝试使用该组的代码,以通过groupdict拉出命名的组。

在一个代码块中嵌入像这样长而复杂的正则表达式确实是不可维护的。我没有试图进一步重构代码,因为我并不假装理解它;但是作为一个开始,您可能想要将庞大的regex拆分为几行,类似

{'descricao':'data_br',
'regex': r'(?:(?:31(?P<sep>/|-|.)(?:0?[13578]|1[02]))(?P=sep)|'
r'(?:(?:29|30)(?P<sep2>/|-|.)(?:0?[1,3-9]|1[0-2])(?P=sep2)))(?:(?:1[6-9]|[2-9]d)?d{2})$|'
r'^(?:29(?P<sep3>/|-|.)0?2(?P=sep3)(?:(?:(?:1[6-9]|[2-9]d)?(?:0[48]|[2468][048]|[13579][26])|'
r'(?:(?:16|[2468][048]|[3579][26])00))))|(?:0?[1-9]|1d|2[0-8])(?P<sep4>/|-|.)'
r'(?:(?:0?[1-9])|(?:1[0-2]))(?P=sep4)(?:(?:1[6-9]|[2-9]d)?d{2})$'
},

更好的是,使用re.X标志并在几行中编写带有嵌入注释的regex。

最新更新