【发布时间】:2011-02-07 22:02:07
【问题描述】:
在 Perl 中,我会做这样的事情来获取正则表达式中的不同字段,用 () 分隔不同的字段并使用 $ 获取它们
foreach $line (@lines)
{
$line =~ m/(.*?):([^-]*)-(.*)/;
$field_1 = $1
$field_2 = $2
$field_3 = $3
}
我怎么能在 Python 中做这样的事情?
【问题讨论】:
在 Perl 中,我会做这样的事情来获取正则表达式中的不同字段,用 () 分隔不同的字段并使用 $ 获取它们
foreach $line (@lines)
{
$line =~ m/(.*?):([^-]*)-(.*)/;
$field_1 = $1
$field_2 = $2
$field_3 = $3
}
我怎么能在 Python 中做这样的事情?
【问题讨论】:
您的 sn-p 的“规范”Python 翻译...:
import re
myre = re.compile(r'(.*?):([^-]*)-(.*)')
for line in lines:
mo = myre.search(line)
field_1, field_2, field_3 = mo.groups()
导入re 是必须的(导入通常在模块顶部完成,但这不是强制性的)。预编译 RE 是可选的(如果您改用 re.search 函数,它将即时编译您的模式)但建议使用(因此您不依赖已编译的 RE 对象的模块缓存来提高性能,并且为了拥有一个 RE 对象并调用其方法,这在 Python 中更为常见)。
您可以使用match 方法(无论您的模式是否以'^' 开头,它总是尝试从头开始匹配)或search 方法(尝试在任何地方进行匹配);对于您给定的模式,它们应该是等效的(但我不是 100% 确定)。
.groups() 方法返回所有匹配的组,因此您可以一次性将它们全部分配(在 Python 中使用列表,就像在 Perl 中使用数组一样,可能更正常,但由于您选择在Perl 你也可以在 Python 中做同样的事情)。
如果任何行与 RE 不匹配,这将失败并出现异常,如果您知道它们都匹配,这很好(我不确定您的 Perl 的行为是什么,但我认为它会“重用”前一个而是匹配行的值,这很奇怪...除非您再次知道所有行都匹配;-)。如果您只想跳过不匹配的行,请将最后一条语句更改为以下两条:
if mo:
field_1, field_2, field_3 = mo.groups()
【讨论】:
在 Perl 中,使用数组比在一堆标量后面加上数字要好得多。例如
foreach my $line ( @lines ) {
my @matches = ( $line =~ m/(.*?):([^-]*)-(.*)/ );
...
}
在 Python 中,re 模块返回一个包含捕获组信息的匹配对象。所以你可以写:
match = re.search( '(.*?):([^-]*)-(.*)', line )
那么您的匹配项将在match.group(1)、match.group(2) 等中提供。
【讨论】:
Python 通过 re 模块支持正则表达式。 re.search() 方法返回一个 MatchObject ,它具有像 group() 这样的方法,您可以使用它们来检索“捕获组”信息。
例如:
m = re.search(r'(.*?):([^-]*)-(.*)', line)
field_1 = m.group(1)
field_2 = m.group(2)
field_3 = m.group(3)
【讨论】:
别忘了在 Python 中,TIMTOWTDI ;)
import re
p = re.compile(r'(\d+)\.(\d+)')
num_parts = p.findall('11.22 333.444') # List of tuples.
print num_parts # [('11', '22'), ('333', '444')]
【讨论】:
import this(即Python之禅,或只是python -c "import this" |grep -i there)
作为一个替代示例,python 为named capture groups 提供了非常好的支持(事实上,python 率先支持命名捕获组)。
要使用命名的捕获组,您只需在捕获组的左括号内添加?P<the_name_of_the_group>。
这使您可以非常轻松地在字典中获取所有匹配项:
>>> import re
>>> x = re.search("name: (?P<name>\w+) age: (?P<age>\d+)", "name: Bob age: 20")
>>> x.groupdict()
{'age': '20', 'name': 'Bob'}
这是 OP 的示例,已修改为使用命名捕获组
import re
find_fields_regex = re.compile(r'(?P<field1>.*?):(?P<field2>[^-]*)-(?P<field3>.*)')
for line in lines:
search_result = find_fields_regex.search(line)
all_the_fields = search_result.groupdict()
现在all_the_fields 是一个字典,其键对应于捕获组名称(“field1”、“field2”和“field3”),值对应于各个捕获组的内容。
为什么你应该更喜欢命名捕获组
>>> import re
>>> x = re.search("name: (?P<name>\w+) age: (?P<age>\d+)", "name: Bob age: 20")
>>> x.groupdict()
{'age': '20', 'name': 'Bob'}
>>> x.group(1)
'Bob'
>>> x.group(2)
'20'
一些不错的正则表达式资源:
【讨论】: