0

I have a string, where

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

and I would like to extract the tuple ('12', 'John'). It is working fine when I am using

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

print m

but I am getting ('2', 'John'), when I am using

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

Why is it going wrong? I mean why .{13} works fine, but .+ fails to work in my re? Thank you!

4

3 回答 3

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']

显然,您需要在多次出现时更好地工作......

于 2012-12-07T18:50:49.577 回答
4

我实际上无法使用您提供的示例文本和正则表达式对此进行测试,因为正如所写的那样,它们显然应该找不到匹配项,实际上在 2.7 和 3.3 中都找不到匹配项。

但我猜你想要一个非贪婪的匹配,改变.+.+?将解决你的问题。

正如乔恩克莱门茨在他的回答中指出的那样,你真的不应该在这里使用正则表达式。正则表达式实际上无法解析 XML 等非常规语言。当然,不管纯粹主义者怎么说,正则表达式仍然可以在快速和肮脏的情况下对非常规语言有用。但是一旦你遇到一些不工作的东西,你应该首先考虑的是这可能不是那些快速和肮脏的情况之一,你应该寻找一个真正的解析器。即使您以前从未使用过ElementTreeAPI 或 XPath,它们也很容易学习,而且学习所花费的时间绝对不会浪费,因为它将来会派上用场很多次。

但无论如何......让我们将您的样本减少到您描述的东西,看看它有什么作用:

>>> 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')]

多田。

于 2012-12-07T18:50:53.020 回答
0

当您使用.+时,它将匹配尽可能多的字符。由于\d+only 需要匹配至少一位数字,因此.+将匹配"="right"><td>1"并只留下 "2" 与\d+.

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

此外,鉴于您似乎正在解析 HTML,您最好使用 BeautifulSoup 之类的东西而不是正则表达式。

于 2012-12-07T18:50:19.313 回答