How to replace repeated instances of a character with a single instance of that character in python

Viewed 26781

I want to replace repeated instances of the "*" character within a string with a single instance of "*". For example if the string is "***abc**de*fg******h", I want it to get converted to "*abc*de*fg*h".

I'm pretty new to python (and programming in general) and tried to use regular expressions and string.replace() like:

import re    
pattern = "***abc**de*fg******h"
pattern.replace("*"\*, "*")

where \* is supposed to replace all instances of the "*" character. But I got: SyntaxError: unexpected character after line continuation character.

I also tried to manipulate it with a for loop like:

def convertString(pattern):
for i in range(len(pattern)-1):
    if(pattern[i] == pattern[i+1]):
        pattern2 = pattern[i]
return pattern2

but this has the error where it only prints "*" because pattern2 = pattern[i] constantly redefines what pattern2 is...

Any help would be appreciated.

11 Answers

I timed all the methods in the current answers (with Python 3.7.2, macOS High Sierra).

b() was the best overall, c() was best when no matches are made.

def b(text):
    re.sub(r"\*\*+", "*", text)

# aka squeeze()
def c(text):
    while "*" * 2 in text:
        text = text.replace("*" * 2, "*")
    return text

Input 1, no repeats: 'a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*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 loops, best of 5: 24.5 usec per loop
  • b) 100000 loops, best of 5: 3.17 usec per loop
  • c) 500000 loops, best of 5: 508 nsec per loop
  • d) 10000 loops, best of 5: 25.4 usec per loop
  • e) 5000 loops, best of 5: 44.7 usec per loop
  • f) 500000 loops, best of 5: 522 nsec per loop

Input 2, with repeats: 'a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*****************************************************************************************************a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*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 loops, best of 5: 46.2 usec per loop
  • b) 50000 loops, best of 5: 5.21 usec per loop
  • c) 20000 loops, best of 5: 13.4 usec per loop
  • d) 5000 loops, best of 5: 47.4 usec per loop
  • e) 2000 loops, best of 5: 103 usec per loop
  • f) 20000 loops, best of 5: 13.1 usec per loop

b() is best overall, c() best if no matches

The methods:

#!/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

text = "aaaaaaaaaabbbbbbbbbbcccccccddddddaaaaaa"

result = " "

for char in text:

if len(result) > 0 and result[-1] == char:
    continue
else:
    result += char

print(result) # abcda

Related