Подтвердить что ты не робот

Заменяйте отдельные экземпляры символов, которые иногда удваиваются

У меня есть строка с каждым символом, разделенным символом канала (включая сами "|"), например:

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

Я хочу заменить все "|", которые не являются рядом с другим "|" ничем, чтобы получить результат:

"funny|boy|a|cat"

Я попытался использовать mytext.replace("|", ""), но это удаляет все и делает одно длинное слово.

4b9b3361

Ответ 1

Это может быть достигнуто с помощью относительно простого регулярного выражения без привязки 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.

Ответ 2

Использовать значения часового пояса

Замените || на ~. Это запомнит ||. Затем удалите | s. Наконец, замените их на |.

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

Еще один лучший способ - использовать тот факт, что они являются почти альтернативным текстом. Решение состоит в том, чтобы сделать их полностью альтернативными...

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

Ответ 3

Вы можете сначала заменить двойной канал чем-то другим, чтобы убедиться, что вы все еще можете распознать их после удаления одиночных труб. И затем вы заменяете их обратно на трубу:

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

Ответ 4

Вы можете использовать позитивный взгляд вперед для замены пипсов, за которыми следует алфавитный символ:

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

Ответ 5

Используйте регулярные выражения.

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

Ответ 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 приведет к содержимому первой группы захвата. Таким образом, вместо единственного пипа, он даст пустую строку и в ||, это принесет второй символ канала.

Другой трюк через границы слов и неслов...

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

Еще один, использующий отрицательный lookbehind..

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

Bonus...

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

Ответ 7

Если вы собираетесь использовать регулярное выражение, самый быстрый метод для разделения и соединения:

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.split и str.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 будет работать независимо от того, какие символы находятся в строке.