替换有时加倍的字符的单个实例

时间:2015-12-25 16:27:39

标签: python regex string replace

我有一个字符串,每个字符由一个竖线字符(包括"|" s本身)分隔,例如:

"f|u|n|n|y||b|o|y||a||c|a|t"

我想替换所有不在"|"旁边的所有"|",以获得结果:

"funny|boy|a|cat"

我尝试使用mytext.replace("|", ""),但这会删除所有内容并生成一个长字。

7 个答案:

答案 0 :(得分:30)

这可以通过相对简单的正则表达式实现,而无需链str.replace

>>> import re
>>> s = "f|u|n|n|y||b|o|y||a||c|a|t"
>>> re.sub('\|(?!\|)' , '', s)
'funny|boy|a|cat'

说明:\ |(?!\ |)将查找|字符,后面没有其他|个字符。 (?!foo)表示负向前瞻,确保你所匹配的任何东西都没有被foo跟随。

答案 1 :(得分:28)

使用哨兵值

||替换为~。这将记住||。然后删除|。最后用|重新替换它们。

>>> s = "f|u|n|n|y||b|o|y||a||c|a|t"
>>> s.replace('||','~').replace('|','').replace('~','|')
'funny|boy|a|cat'

另一种更好的方法是使用它们几乎是替代文本的事实。解决方案是让它们完全交替......

s.replace('||','|||')[::2] 

答案 2 :(得分:24)

您可以先用其他东西替换双管,以确保在移除单个管道后仍能识别它们。然后你将它们换回管道:

>>> t = "f|u|n|n|y||b|o|y||a||c|a|t"
>>> t.replace('||', '|-|').replace('|', '').replace('-', '|')
'funny|boy|a|cat'

您应该尝试选择一个安全临时值的替换值,并且不会自然地出现在您的文本中。否则,即使它最初不是双管,您也会遇到替换该字符的冲突。因此,如果您的文字可能包含短划线,请不要使用上述短划线。您也可以同时使用多个字符,例如:'<THIS IS A TEMPORARY PIPE>'

如果你想完全避免这种冲突,你也可以解决这个问题。例如,您可以先通过双管道拆分字符串,然后对每个子字符串执行替换,最终将它们重新连接在一起:

>>> '|'.join([s.replace('|', '') for s in t.split('||')])
'funny|boy|a|cat'

当然,您也可以使用正则表达式来替换那些未被其他管道跟随的管道:

>>> import re
>>> re.sub('\|(?!\|)', '', t)
'funny|boy|a|cat'

答案 3 :(得分:11)

您可以使用positive look ahead正则表达式替换后跟字母字符的点数:

>>> import re
>>> st = "f|u|n|n|y||b|o|y||a||c|a|t" 
>>> re.sub(r'\|(?=[a-z]|$)',r'',st)
'funny|boy|a|cat'

答案 4 :(得分:6)

使用正则表达式。

import re

line = "f|u|n|n|y||b|o|y||a||c|a|t" 
line = re.sub("(?!\|\|)(\|)", "", line)

print(line)

输出:

funny|boy|a|cat

答案 5 :(得分:6)

捕获组的另一个正则表达式选项。

>>> import re
>>> re.sub(r'\|(\|?)', r'\1', "f|u|n|n|y||b|o|y||a||c|a|t")
'funny|boy|a|cat'

<强>解释

\| - 匹配所有管道字符。 (\|?) - 捕获以下管道字符(如果存在)。然后用\1替换匹配将为您带来第一个捕获组的内容。因此,在单个pip的位置,它将给出一个空字符串,在||中,它将带来第二个管道字符。

通过单词和非单词边界的另一个技巧......

>>> re.sub(r'\b\|\b|\b\|\B', '', "f|u|n|n|y||b|o|y||a||c|a|t|")
'funny|boy|a|cat'

还有一个使用负面看法......

>>> re.sub(r'(?<!\|)\|', '', "f|u|n|n|y||b|o|y||a||c|a|t|")
'funny|boy|a|cat'

...奖金

>>> re.sub(r'\|(\|)|\|', lambda m: m.group(1) if m.group(1) else '', "f|u|n|n|y||b|o|y||a||c|a|t")
'funny|boy|a|cat'

答案 6 :(得分:4)

如果您打算使用正则表达式,最快的方法是拆分和加入:

In [18]: r = re.compile("\|(?!\|)")

In [19]: timeit "".join(r.split(s))
100000 loops, best of 3: 2.65 µs per loop
In [20]:  "".join(r.split(s))
Out[20]: 'funny|boy|a|cat'
In [30]: r1 = re.compile('\|(?!\|)')

In [31]: timeit r1.sub("", s)
100000 loops, best of 3: 3.20 µs per loop

In [33]: r2 = re.compile("(?!\|\|)(\|)")
In [34]: timeit r2.sub("",s)
100000 loops, best of 3: 3.96 µs per loop

str.splitstr.replace方法仍然更快:

In [38]: timeit '|'.join([ch.replace('|', '') for ch in s.split('||')])
The slowest run took 11.18 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 1.71 µs per loop

In [39]: timeit s.replace('||','|||')[::2]
1000000 loops, best of 3: 536 ns per loop

In [40]: timeit s.replace('||','~').replace('|','').replace('~','|')
1000000 loops, best of 3: 881 ns per loop

取决于字符串中的内容将决定str.replace方法,但无论字符串中包含哪些字符,str.split方法都将起作用。