用适当的替换贪婪的元素

时间:2018-01-12 02:38:58

标签: python regex

我有以下列表:

import re
l = ['Part I,   Where I’M Coming From',
 'Part Ii,  Life Principles',
 'Part Iii, Work Principles']

我想要一个结果,

l = ['Part I,   Where I’M Coming From',
     'Part II,  Life Principles',
     'Part III, Work Principles']

我试过了:

In [19]: [re.sub(r'(?<=I)i+', 'I+', s) for s in l]
Out[19]:
['Part I,   Where I’M Coming From',
 'Part II+,  Life Principles',
 'Part II+, Work Principles']

输出'Part II+, Work Principles'而非'Part III, Work Principles'

如何完成这项任务?

2 个答案:

答案 0 :(得分:2)

执行此操作的一种简单方法是将re.sub回调功能一起使用。除简单替换之外,回调处理更复杂的逻辑。在您的情况下,您需要匹配大写i之后的所有小写I,找出有多少i个,并相应地替换。

>>> re.sub('(?<=I)(i+)', lambda x: 'I' * len(x.group()), 'Part Iii,  Work Principles')
'Part III,  Work Principles'

如果没有匹配,则不会调用回调(即,不会发生替换)。

如果您对更深入了解所发生的事情感兴趣,可以使用几个打印语句进行与函数相同的回调。

>>> def replace(m):
...     print(*[m, m.group(), len(m.group())], sep='\n')
...     return 'I' * len(m.group())
... 
>>> re.sub('(?<=I)(i+)', replace, 'Part Iii,  Work Principles')
<_sre.SRE_Match object; span=(6, 8), match='ii'>
ii
2
'Part III,  Work Principles'

你会注意到这打印出来......

<_sre.SRE_Match object; span=(6, 8), match='ii'>
ii
2

......除了进行更换。需要注意的重要一点是它将match对象传递给回调函数。然后,您可以找出匹配的 ,并相应地决定要替换它的内容。

对任意罗马数字的推广

如果您的功能必须匹配任何罗马数字,那么您可以pass a pattern that finds thosere.sub,但您的回调会大大简化:

>>> p = r'\bM{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})\b'
>>> string = 'Part viiI,  Work Principles'
>>> re.sub(p, lambda x: x.group().upper(), string, flags=re.IGNORECASE)
'Part VIII,  Work Principles'

现在,您需要做的只是将匹配的字符串大写。

答案 1 :(得分:0)

一种选择是简单地使用re.split,应用str.upper,然后使用str.format

import re
l = ['Part I,   Where I’M Coming From',
'Part Ii,  Life Principles',
'Part Iii, Work Principles']
new_l = [re.split('(?<=Part)\s|,\s+', i) for i in l]
final_l = ['{} {},  {}'.format(a, b.upper(), c) for a, b, c in new_l]

输出:

l = ['Part I,   Where I’M Coming From',
 'Part II,  Life Principles',
 'Part III, Work Principles']