2010-10-07 16 views
12

Quiero reemplazar instancias repetidas del carácter "*" dentro de una cadena con una sola instancia de "*". Por ejemplo, si la cadena es "***abc**de*fg******h", quiero que se convierta a "*abc*de*fg*h".Cómo reemplazar instancias repetidas de un carácter con una instancia única de ese carácter en python

estoy bastante nuevo en Python (y la programación en general) y trató de usar expresiones regulares y String.Replace() como:

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

donde \* se supone que reemplazar todas las instancias de la "* " personaje. Pero obtuve: SyntaxError: carácter inesperado después del carácter de continuación de línea.

También trató de manipularlo con un bucle for como:

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

pero esto tiene el error en el que sólo imprime "*" porque patrón2 = patrón [i] redefine constantemente lo que es patrón2 ...

Cualquier ayuda sería apreciada.

Respuesta

4

me gustaría sugerir el uso de la función re module substitución:

import re 

result = re.sub("\*+", "*", "***abc**de*fg******h") 

Te recomiendo la lectura a través del artículo trata de RE y las buenas prácticas. Pueden ser difíciles si no estás familiarizado con ellos. En la práctica, usar cadenas sin formato es una buena idea.

+0

Muchas gracias, esto funciona bien, voy a leer el artículo sobre RE para averiguar qué está pasando exactamente con la parte "\ +" del código. No sabía que podrías usar múltiples símbolos en conjunto. Pensé que solo podrías usar "+" o "*" por ejemplo. – NSchrading

+2

@NSchrading: en '" \\ * + "', estoy escapando del * carácter porque es un símbolo de re especial. Así que comparo un carácter literal *, y el + significa uno o más. – JoshD

0
re.sub('\*+', '*', pattern) 

Eso hará.

1

Expresiones bien regulares sabias que haría exactamente lo que JoshD ha sugerido. Pero una mejora aquí.

Uso -

regex = re.compile('\*+') 
result = re.sub(regex, "*", string) 

Esto habría caché esencialmente su expresión regular. Por lo tanto, el uso posterior de esto en un bucle haría que sus operaciones regex sean rápidas.

+1

Esta es una optimización prematura. Python almacena en caché las expresiones compiladas recientemente utilizadas de todos modos. – kindall

0

sin expresión regular puede utilizar la eliminación general elemento repetido con la comprobación de '*':

source = "***abc**dee*fg******h" 
target = ''.join(c for c,n in zip(source, source[1:]+' ') if c+n != '**') 
print target 
4

¿qué hay de una manera no regex

def squeeze(char,s): 
    while char*2 in s: 
     s=s.replace(char*2,char) 
    return s 
print squeeze("*" , "AB***abc**def**AA***k") 
14

La forma ingenua de hacer este tipo de cosas con re es

re.sub('\*+', '*', text) 

que reemplaza carreras de 1 o más asteriscos con un asterisco. Para ejecuciones de exactamente un asterisco, se está ejecutando muy duro solo para permanecer quieto. Mucho mejor es reemplazar carreras de dos o más asteriscos por un solo asterisco:

re.sub('\*\*+', '*', text) 

Esto puede ser bien vale la pena:

\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 

Nota que re.Sub devolverá una referencia a la cadena de entrada si no ha encontrado coincidencias, lo que ahorrará más desgaste en su computadora, en lugar de una cadena completamente nueva.

+0

+1 Es un buen consejo. Aunque para un Joe promedio que quizás no esté haciendo esto miles de veces por segundo, la diferencia apenas importa. El primero gana en legibilidad. Así que sugeriría, no use ciegamente lo último. – Medorator

+1

@Medorator No estoy seguro de la legibilidad ... una vez que JAvg entiende '\ X', el salto a' \ X \ X' me parece minúsculo. Quizás '\ X {2,}' sería mejor? Espero que JAvg no haga nada a ciegas. Si el requisito de salida cambió a "encontrar todas las apariciones de asteriscos repetidos", le gustaría pensar que la expresión regular cambió de 1+ a 2+. –

1

Usted escribió:

pattern.replace("*"\*, "*") 

que quería decir:

pattern.replace("\**", "*") 
#    ^^^^ 

Realmente significaba:

pattern_after_substitution= re.sub(r"\*+", "*", pattern) 

que no lo que quería.

0

Supongamos por este ejemplo que tu personaje es un espacio.

También puede hacerlo de esta manera:

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 

Este:

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 

se convierte en:

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 

Me parece que esto es un poco más fácil que tener que ensuciar alrededor con el módulo re, que a veces puede ser un poco molesto (creo).

Espero que haya sido útil.

0

Esto funcionará para cualquier número de asteriscos consecutivos, aunque es posible que deba reemplazar la tilde con alguna otra cadena que sepa que será única en toda la cadena.

string = "begin*************end" 

    string.replace("**", "~*").replace("*~", "").replace("~*", "*").replace("**", "*") 

creo enfoques de expresiones regulares serían generalmente más costoso computacionalmente que esto.

Cuestiones relacionadas