“”和“+”不能正常工作

时间:2012-12-07 18:44:26

标签: python regex

我有一个字符串,其中

text='<tr align="right"><td>12</td><td>John</td> 

我想提取元组('12','John')。我使用时工作正常

m=re.findall(r'align.{13}(\d+).*([A-Z]\w+).*([A-Z]\w+)', text)

打印m

但是当我使用

时,我得到('2','John')
m=re.findall(r'align.+(\d+).*([A-Z]\w+).*([A-Z]\w+)', text)
print m

为什么会出错?我的意思是为什么。{13}工作正常,但是。+无法在我的工作中工作? 谢谢!

3 个答案:

答案 0 :(得分:5)

你应该为此使用正确的HTML解析器库,即:

>>> a = '<tr align="right"><td>12</td><td>John</td>'
>>> p = lxml.html.fromstring(a)
>>> p.text_content()
'12John'
>>> p.xpath('//td/text()')
['12', 'John']

显然,你需要多次出现这种情况......

答案 1 :(得分:4)

我实际上无法使用您提供的示例文本和正则表达式对此进行测试,因为编写时他们显然不会找到匹配项,事实上在2.7和3.3中都找不到匹配项。

但我猜你想要一场非贪婪的比赛,将.+改为.+?会解决你的问题。

正如Jon Clements在答案中指出的那样,你真的不应该在这里使用正则表达式。 Regexp实际上无法解析像XML这样的非常规语言。当然,尽管纯粹主义者说,在快速和肮脏的情况下,正则表达式对于非常规语言仍然是一个有用的黑客。但是当你遇到一些无效的东西时,首先想到你应该做的就是考虑这可能不是那些快速和肮脏的情况之一,你应该寻找一个真正的解析器。即使您以前从未使用过ElementTree API,或者XPath,它们也很容易学习,学习所花费的时间绝对不会浪费,因为它将来会多次派上用场。 / p>

但无论如何......让我们将你的样本减少到你所描述的那样的东西,并看看它的作用:

>>> text='<tr align="right"><td>12</td><td>John</td> 
SyntaxError: EOL while scanning string literal
>>> text='<tr align="right"><td>12</td><td>John</td>'
>>> re.findall(r'align.{13}(\d+).*([A-Z]\w+).*([A-Z]\w+)', text)
[]
>>> re.findall(r'align.{13}(\d+).*([A-Z]\w+)', text)
[('12', 'John')]
>>> re.findall(r'align.+(\d+).*([A-Z]\w+).*([A-Z]\w+)', text)
[]
>>> re.findall(r'align.+(\d+).*([A-Z]\w+)', text)
[('2', 'John')]

我认为这就是你所抱怨的。那么,.+并非“不正常”;它完全按照你的要求进行:匹配至少一个字符,并尽可能多地匹配表达式的其余部分仍然需要匹配的点。其中包括匹配1,因为表达式的其余部分仍然匹配。

如果你想让它在表达的其余部分接管后立即停止匹配,那就是非贪婪的匹配,而不是贪婪的匹配,所以你需要+?而不是+ 。我们来试试吧:

>>> re.findall(r'align.+?(\d+).*([A-Z]\w+)', text)
[('12', 'John')]

多田。

答案 2 :(得分:0)

使用.+时,它会匹配尽可能多的字符。由于\d+只需匹配至少一位数字,.+将匹配"="right"><td>1",只留下“{2}”与\d+匹配。

您的原始示例适用于您的示例数据。如果您需要编写适用于其他数据的正则表达式,您需要解释该数据的格式是什么以及您希望如何决定要提取的部分。

另外,鉴于您似乎正在解析HTML,您可能最好使用BeautifulSoup而不是正则表达式。