Python正则表达式 - 完全匹配

1 投票
3 回答
749 浏览
提问于 2025-04-16 03:51

在我的CGI应用程序中,我正在写一个函数,用来获取浏览器的首选语言,这个信息保存在HTTP_ACCEPT_LANGUAGE这个变量里。我想用正则表达式找到这个变量中的所有语言标签(语言标签的一般格式在RFC1766中有定义)。RFC1766中的EBNF规则('1*8ALPHA'表示一个到八个ASCII字符):

Language-Tag = Primary-tag *( "-" Subtag )
Primary-tag = 1*8ALPHA
Subtag = 1*8ALPHA

我为语言标签写了这个正则表达式:

(([a-z]{1,8})(-[a-z]{1,8})*)

如果我使用这个表达式,Python的re模块会给出以下结果:

>>import re

>>re.findall("(([a-z]{1,8})(-[a-z]{1,8})*)", "x-pig-latin en-us de-de en", re.IGNORECASE)
[('x-pig-latin', 'x', '-latin'), ('en-us', 'en', '-us'), ('de-de', 'de', '-de'), ('en', 'en', '')]

结果是正确的。但是我只需要完整的匹配,比如'de-de'或者'x-pig-latin'。我可以假设一个组的第一个匹配总是最完整的吗?或者有没有什么标志可以让re显示最完整的匹配结果?

Stefan

3 个回答

0

不确定你是否已经查看过,但这篇文章提供了很多关于如何处理Accept-Language解析的好建议,还有一个库的参考,那个库已经解决了这个问题。

至于你提到的re问题,Doug Hellman在他最近的Python每周模块中对re做了一个很棒的解析

2

把你内部的括号(也就是小括号)改成捕获的类型:也就是说,把下面的:

(([a-z]{1,8})(-[a-z]{1,8})*)

改成:

((?:[a-z]{1,8})(?:-[a-z]{1,8})*)

简单来说,模式符号 (?: ... ) 定义了一个捕获的组:这些小括号仍然可以用来控制优先级,但它们不会在匹配结果的 .groups() 和其他与捕获组相关的特性中留下痕迹。

普通的小括号 ( ... ) 表示一个捕获组。

当然,对于那些你明确感兴趣的子匹配,使用捕获组是没有必要的。只对你关心的子匹配使用捕获组!-)

4

你可以使用 ?: 这个操作符来防止正则表达式引擎保存括号里的子模式:

((?:[a-z]{1,8})(?:-[a-z]{1,8})*)

这样会得到以下输出:

re.findall("((?:[a-z]{1,8})(?:-[a-z]{1,8})*)", "x-pig-latin en-us de-de en", re.IGNORECASE)
['x-pig-latin', 'en-us', 'de-de', 'en']

回答你的问题,findall 返回的第一个匹配结果应该是完整的匹配子串。

撰写回答