Python替换未确定长度的文本

时间:2012-03-01 07:30:11

标签: python regex replace substitution

我有一个这样的字符串:

Hi. My name is _John_. I am _20_ years old.

我希望将其转换为:

Hi. My name is <b>John</b>. I am <b>20</b> years old.

我做了类似的事,但没有运气。

import re
text = "Hi. My name is _John_. I am _20_ years old."
pattern = "(.*)(\_)(.*)(\_)(.*)"
re.sub(pattern, r'\1<b>\3</b>\5', text)
'Hi. My name is _John_. I am <b>20</b> years old.'

模式有什么问题?为什么没有看到第一个粗体文字?

任何帮助将不胜感激。 感谢。

6 个答案:

答案 0 :(得分:4)

问题是*贪婪并消耗尽可能多的字符(包括更多_)。要解决此问题,您可以使用非贪婪的替代*?,如下所示:

>>> pattern = r'_(.*?)_'
>>> replacement = r'<b>\1</b>'
>>> re.sub(pattern ,replacement, text)
'Hi. My name is <b>John</b>. I am <b>20</b> years old.'

请注意,re.sub的行为与re.search相似,而不是re.match。也就是说,您可以使用仅与输入部分匹配的模式(在这种情况下,只是一些由_包围的文本)而不是与整行匹配的内容。

答案 1 :(得分:4)

更改为:

pattern = "_([^_]*)_"
re.sub(pattern, r'<b>\1</b>', text)

另见this example

答案 2 :(得分:3)

问题在于你模式中的第一个.*正在吃最后一个可能匹配左边的所有内容。因此,据说* 贪婪。使用非贪婪模式

pattern='_(.+?)_'
re.sub(pattern, r'<b>\1</b>', text)

?使匹配非贪婪;尽可能短。 +在两个下划线之间的东一个字符处需要,以便用<b>text</b>替换它。因此__将保持__

如果您希望__成为<b></b>,请使用.*?

答案 3 :(得分:3)

您是否尝试过使用String Templates?他们是为这样的东西而建造的。简单的字符串替换。很多清洁的地狱&amp;优雅而不是使用正则表达式...

import string

new_style = string.Template('Hi. My name is $name. I am $age years old.')
print new_style % {'name':'<b>John</b>', 'age':'<b>20</b>'} #produces what u want.

有关字符串模板示例的更多信息,请查看此activeState link

答案 4 :(得分:2)

这是因为模式是贪心,第一个(.*)匹配从开头一直到第三个_的文字:

>>> re.match(pattern, text).groups()
('Hi. My name is _John_. I am ', '_', '20', '_', ' years old.')

这是一个简化的非贪婪版本:

>>> re.sub('_(.+?)_', r'<b>\1</b>', text)
'Hi. My name is <b>John</b>. I am <b>20</b> years old.'

答案 5 :(得分:1)

这听起来非常像markdown syntax,所以如果您的目标是解析它,那么就已存在python library