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

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

Любая помощь будет оценена.

4b9b3361

Ответ 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