在Python正则表达式中使用^匹配行的开头

43
我试图从汤姆森路透Web of Science中提取ISI风格的出版年份数据。 "出版年份"这一行看起来像这样(位于一行的最开头):


PY 2015

我正在编写的脚本中,我定义了以下的正则表达式函数:

import re
f = open('savedrecs.txt')
wosrecords = f.read()

def findyears():
    result = re.findall(r'PY (\d\d\d\d)', wosrecords)
    print result

findyears()

然而,这会导致误报,因为该模式可能出现在数据的其他位置。

所以,我想只匹配行首的模式。通常情况下我会使用^来达到这个目的,但是r'^PY (\d\d\d\d)'没有匹配到我的结果。另一方面,使用\n似乎可以实现我想要的效果,但这可能会给我带来进一步的复杂性。


11
使用re.MULTILINE来改变^的语义:re.findall(r'^PY (\d\d\d\d)', wosrecords, re.MULTILINE) - Amadan
3个回答

48
re.findall(r'^PY (\d\d\d\d)', wosrecords, flags=re.MULTILINE)

应该能够正常工作


为什么要使用flags=re.MULTILINE?没有它的话,就无法正常工作。 - undefined

11

您可以在模式的开头简单地添加(?m) 内联修饰符标志

(?m)^PY\s+(\d{4})
^^^^

不要与 (?s) 混淆! (?s) 是一个DOTALL内联标志,使. 匹配包括换行符在内的任何字符。

或者,您可以使用re.Mre.MULTILINE选项来进行re.search

import re
p = re.compile(r'^PY\s+(\d{4})', re.M)
test_str = "PY123\nPY 2015\nPY 2017"
print(re.findall(p, test_str)) 

请参见IDEONE演示.


1
是的,这也应该可以工作。我错过的是re.M或re.MULTILINE标志,我不知道它会影响^符号。 - chrisk
实际上,re.M 的唯一功能就是强制 ^$ 分别在行的开头和结尾(\n 之前)匹配。 - Wiktor Stribiżew

2
在这种情况下,不需要使用正则表达式,因为搜索的字符串始终为“PY”,并且预计在行的开头,因此可以使用string.find来完成此任务。 find函数返回给定字符串或行中找到子字符串的位置,因此如果在字符串开头找到它,则返回值为0(如果根本没有找到,则返回-1),即:
In [12]: 'PY 2015'.find('PY')
Out[12]: 0

In [13]: ' PY 2015'.find('PY')
Out[13]: 1

也许去掉空格会是一个不错的主意,即:
In [14]: '  PY 2015'.find('PY')
Out[14]: 2

In [15]: '  PY 2015'.strip().find('PY')
Out[15]: 0

接下来,如果只对年份感兴趣,则可以使用split进行提取,即:

In [16]: '  PY 2015'.strip().split()[1]
Out[16]: '2015'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接