Как заменить повторяющиеся экземпляры символа одним экземпляром этого символа в python
Я хочу заменить повторяющиеся экземпляры символа "*"
в строке одним экземпляром "*"
. Например, если строка "***abc**de*fg******h"
, я хочу, чтобы она преобразуется в "*abc*de*fg*h"
.
Я новичок в python (и вообще программировании) и пытался использовать регулярные выражения и string.replace() как:
import re
pattern = "***abc**de*fg******h"
pattern.replace("*"\*, "*")
где \*
предполагается заменить все экземпляры символа "*". Но я получил: SyntaxError: неожиданный символ после символа продолжения строки.
Я также пытался манипулировать им с помощью цикла for, например:
def convertString(pattern):
for i in range(len(pattern)-1):
if(pattern[i] == pattern[i+1]):
pattern2 = pattern[i]
return pattern2
но это имеет ошибку, когда она печатает только "*", потому что pattern2 = pattern [i] постоянно переопределяет, что шаблон2...
Любая помощь будет оценена.
Ответы
Ответ 1
Наивный способ сделать это с помощью re
-
re.sub('\*+', '*', text)
Это заменяет пробеги 1 или более звездочек с одним звездочкой. Для прогонов точно одной звездочки, которая работает очень тяжело, чтобы оставаться неподвижным. Намного лучше заменить пробелы звездочек TWO или более одной звездочкой:
re.sub('\*\*+', '*', text)
Это может стоить того:
\python27\python -mtimeit -s"t='a*'*100;import re" "re.sub('\*+', '*', t)"
10000 loops, best of 3: 73.2 usec per loop
\python27\python -mtimeit -s"t='a*'*100;import re" "re.sub('\*\*+', '*', t)"
100000 loops, best of 3: 8.9 usec per loop
Обратите внимание, что re.sub вернет ссылку на входную строку, если не найдет совпадений, сохраняя больше износа на вашем компьютере, а не целую новую строку.
Ответ 2
как насчет пути без регулярного выражения
def squeeze(char,s):
while char*2 in s:
s=s.replace(char*2,char)
return s
print squeeze("*" , "AB***abc**def**AA***k")
Ответ 3
Я бы предложил использовать функцию re module:
import re
result = re.sub("\*+", "*", "***abc**de*fg******h")
Я очень рекомендую прочитать статью о RE и передовой практике. Они могут быть сложными, если вы не знакомы с ними. На практике использование исходных строк - хорошая идея.
Ответ 4
Вы писали:
pattern.replace("*"\*, "*")
Вы имели в виду:
pattern.replace("\**", "*")
# ^^^^
Вы действительно имели в виду:
pattern_after_substitution= re.sub(r"\*+", "*", pattern)
который делает то, что вы хотели.
Ответ 5
Хорошо регулярные выражения, я бы сделал то же, что предложил JoshD. Но одно улучшение здесь.
Использование -
regex = re.compile('\*+')
result = re.sub(regex, "*", string)
Это, по сути, кэширует ваше регулярное выражение. Поэтому последующее использование этого в цикле сделало бы ваши регулярные операции быстрыми.
Ответ 6
re.sub('\*+', '*', pattern)
Это сделает.
Ответ 7
без regexp вы можете использовать общее удаление повторяющегося элемента с проверкой '*':
source = "***abc**dee*fg******h"
target = ''.join(c for c,n in zip(source, source[1:]+' ') if c+n != '**')
print target
Ответ 8
Предположим для этого в этом примере ваш персонаж - это пробел.
Вы также можете сделать это следующим образом:
while True:
if " " in pattern: # if two spaces are in the variable pattern
pattern = pattern.replace(" ", " ") # replace two spaces with one
else: # otherwise
break # break from the infinite while loop
Это:
File Type : Win32 EXE
File Type Extension : exe
MIME Type : application/octet-stream
Machine Type : Intel 386 or later, and compatibles
Time Stamp : 2017:04:24 09:55:04-04:00
становится:
File Type : Win32 EXE
File Type Extension : exe
MIME Type : application/octet-stream
Machine Type : Intel 386 or later, and compatibles
Time Stamp : 2017:04:24 09:55:04-04:00
Я считаю, что это немного легче, чем сбрасывать с помощью модуля re, который иногда может немного раздражать (я думаю).
Надеюсь, что это было полезно.
Ответ 9
Это будет работать для любого количества последовательных звездочек, хотя вам может потребоваться заменить тильду другой строкой, которая, как вы знаете, будет уникальной во всей строке.
string = "begin*************end"
string.replace("**", "~*").replace("*~", "").replace("~*", "*").replace("**", "*")
Я считаю, что подходы к регулярному выражению, как правило, будут более дорогостоящими, чем это.
Ответ 10
Я рассчитал все методы в текущих ответах (с Python 3.7.2, macOS High Sierra).
b()
был лучшим в целом, c()
был лучшим, когда не найдено совпадений.
def b(text):
re.sub(r"\*\*+", "*", text)
# aka squeeze()
def c(text):
while "*" * 2 in text:
text = text.replace("*" * 2, "*")
return text
Ввод 1, повторений нет: 'a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*'
- а) 10000 петель, лучшее из 5: 24,5 мксек на петлю
- б) 100000 циклов, лучшее из 5: 3,17 циклов на цикл
- в) 500000 циклов, лучшее из 5: 508 нс на цикл
- d) 10000 петель, лучшее из 5: 25,4 мксек на петлю
- e) 5000 петель, лучшее из 5: 44,7 мксек на петлю
- f) 500000 циклов, лучшее из 5: 522 нс на цикл
Вход 2, с повторениями: 'a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*****************************************************************************************************a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*'
- а) 5000 петель, лучшее из 5: 46,2 мксек на петлю
- б) 50000 петель, лучшее из 5: 5,21 юсек на петлю
- в) 20000 циклов, лучшее из 5: 13,4 на цикл
- d) 5000 петель, лучшее из 5: 47,4 на одну петлю
- д) 2000 циклов, лучшее из 5: 103 мксек на цикл
- f) 20000 циклов, лучшее из 5: 13,1 циклов на цикл
![b() is best overall, c() best if no matches]()
Методы:
#!/usr/bin/env python
# encoding: utf-8
"""
See which function variants are fastest. Run like:
python -mtimeit -s"import time_functions;t='a*'*100" "time_functions.a(t)"
python -mtimeit -s"import time_functions;t='a*'*100" "time_functions.b(t)"
etc.
"""
import re
def a(text):
return re.sub(r"\*+", "*", text)
def b(text):
re.sub(r"\*\*+", "*", text)
# aka squeeze()
def c(text):
while "*" * 2 in text:
text = text.replace("*" * 2, "*")
return text
regex = re.compile(r"\*+")
# like a() but with (premature) optimisation
def d(text):
return re.sub(regex, "*", text)
def e(text):
return "".join(c for c, n in zip(text, text[1:] + " ") if c + n != "**")
def f(text):
while True:
if "**" in text: # if two stars are in the variable pattern
text = text.replace("**", "*") # replace two stars with one
else: # otherwise
break # break from the infinite while loop
return text