2012-03-01 48 views
2

未确定的长度我有一个这样的字符串:Python的替换文本

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

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

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

回答

4

更改为:

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

另见this example

3

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

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

?使得比赛非贪婪;尽可能短。 +要求在两个下划线之间的东部一个字符处,以便将其替换为<b>text</b>。所以__仍将__

如果您想__成为<b></b>然后用.*?

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.' 
+0

+1。非常感谢。 – ozgur 2012-03-01 07:46:24

+0

如果您在字符串中间搜索某些东西(与'.search'或'.sub'或'.findall'一样,那么在正则表达式之前添加“之前和之后的任何内容”没有任何意义 – 2012-03-01 08:49:33

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。也就是说,您可以使用与输入部分匹配的模式(在这种情况下,只包含由_包围的一些文本),而不是与整行相匹配的模式。

3

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

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

1

这听起来非常像markdown syntax,所以如果你的目标是解析,那就已经存在了一个python library

+0

+1建议一个库 – Kimvais 2012-03-01 07:48:44

+0

比markdown thingy更多。我觉得这更接近于python字符串模板,请检查 - http://www.python.org/dev/peps/pep-0292/ – 2012-03-01 07:55:34