Eliminar una lista de caracteres en cadena

217

Quiero eliminar caracteres en una cadena en python:

string.replace(',', '').replace("!", '').replace(":", '').replace(";", '')...

Pero tengo muchos personajes que tengo que eliminar. Pensé en una lista

list = [',', '!', '.', ';'...]

Pero, ¿cómo puedo usar el listpara reemplazar los caracteres en el string?

Laura
fuente
66
Consulte stackoverflow.com/questions/1919096/… para obtener varias soluciones y una buena comparación.
Martijn de Milliano
Es una pena que Python (que se dice que viene con baterías incluidas) no maneja este caso de uso fuera de la caja. La función str_replace de PHP lo hace: puede pasar una matriz como primer argumento y una cadena como el segundo ( php.net/manual/pl/function.str-replace.php ).
JustAC0der

Respuestas:

265

Si está utilizando python2 y sus entradas son cadenas (no unicodes), el mejor método es str.translate:

>>> chars_to_remove = ['.', '!', '?']
>>> subj = 'A.B!C?'
>>> subj.translate(None, ''.join(chars_to_remove))
'ABC'

De lo contrario, hay siguientes opciones a considerar:

A. Itere el tema char por char, omita los caracteres no deseados y joinla lista resultante:

>>> sc = set(chars_to_remove)
>>> ''.join([c for c in subj if c not in sc])
'ABC'

(Tenga en cuenta que la versión del generador ''.join(c for c ...) será menos eficiente).

B. Cree una expresión regular sobre la marcha y re.subcon una cadena vacía:

>>> import re
>>> rx = '[' + re.escape(''.join(chars_to_remove)) + ']'
>>> re.sub(rx, '', subj)
'ABC'

( re.escapeasegura que los caracteres como ^o] no rompan la expresión regular).

C. Use la variante de mapeo detranslate :

>>> chars_to_remove = [u'δ', u'Γ', u'ж']
>>> subj = u'AжBδCΓ'
>>> dd = {ord(c):None for c in chars_to_remove}
>>> subj.translate(dd)
u'ABC'

Código de prueba completo y tiempos:

#coding=utf8

import re

def remove_chars_iter(subj, chars):
    sc = set(chars)
    return ''.join([c for c in subj if c not in sc])

def remove_chars_re(subj, chars):
    return re.sub('[' + re.escape(''.join(chars)) + ']', '', subj)

def remove_chars_re_unicode(subj, chars):
    return re.sub(u'(?u)[' + re.escape(''.join(chars)) + ']', '', subj)

def remove_chars_translate_bytes(subj, chars):
    return subj.translate(None, ''.join(chars))

def remove_chars_translate_unicode(subj, chars):
    d = {ord(c):None for c in chars}
    return subj.translate(d)

import timeit, sys

def profile(f):
    assert f(subj, chars_to_remove) == test
    t = timeit.timeit(lambda: f(subj, chars_to_remove), number=1000)
    print ('{0:.3f} {1}'.format(t, f.__name__))

print (sys.version)
PYTHON2 = sys.version_info[0] == 2

print ('\n"plain" string:\n')

chars_to_remove = ['.', '!', '?']
subj = 'A.B!C?' * 1000
test = 'ABC' * 1000

profile(remove_chars_iter)
profile(remove_chars_re)

if PYTHON2:
    profile(remove_chars_translate_bytes)
else:
    profile(remove_chars_translate_unicode)

print ('\nunicode string:\n')

if PYTHON2:
    chars_to_remove = [u'δ', u'Γ', u'ж']
    subj = u'AжBδCΓ'
else:
    chars_to_remove = ['δ', 'Γ', 'ж']
    subj = 'AжBδCΓ'

subj = subj * 1000
test = 'ABC' * 1000

profile(remove_chars_iter)

if PYTHON2:
    profile(remove_chars_re_unicode)
else:
    profile(remove_chars_re)

profile(remove_chars_translate_unicode)

Resultados:

2.7.5 (default, Mar  9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)]

"plain" string:

0.637 remove_chars_iter
0.649 remove_chars_re
0.010 remove_chars_translate_bytes

unicode string:

0.866 remove_chars_iter
0.680 remove_chars_re_unicode
1.373 remove_chars_translate_unicode

---

3.4.2 (v3.4.2:ab2c023a9432, Oct  5 2014, 20:42:22) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]

"plain" string:

0.512 remove_chars_iter
0.574 remove_chars_re
0.765 remove_chars_translate_unicode

unicode string:

0.817 remove_chars_iter
0.686 remove_chars_re
0.876 remove_chars_translate_unicode

(Como nota al margen, la cifra remove_chars_translate_bytespodría darnos una pista de por qué la industria era reacia a adoptar Unicode durante tanto tiempo).

georg
fuente
1
El segundo método genera un error TypeError: translate() takes exactly one argument (2 given). Aparentemente toma dict como argumento.
antonavy
@antonavy: la segunda solución funciona, pero solo la cadena no es unicode (para lo cual se necesita un traductor diferente)
FuzzyAmi
112

Puedes usar str.translate():

s.translate(None, ",!.;")

Ejemplo:

>>> s = "asjo,fdjk;djaso,oio!kod.kjods;dkps"
>>> s.translate(None, ",!.;")
'asjofdjkdjasooiokodkjodsdkps'
Sven Marnach
fuente
19
@ thg435: Nadie pidió esto, pero de todos modos:s.translate(dict.fromkeys(map(ord, u",!.;")))
Sven Marnach
2
Esta (y la respuesta simultánea de @ PraveenGollakota) es exactamente lo que pidió @Laura y debería ser la (s) respuesta (s) preferida (s).
Hobs
77
por qué python3: TypeError: translate () toma exactamente un argumento (2 dados)
Gank
2
@Gank: El unicode.translate()método tiene diferentes parámetros que el str.translate()método. Use la variante en el comentario anterior para los objetos Unicode.
Sven Marnach
@SvenMarnach ¿Qué es el mapa (ord, u ",!.;"))? y representas unicode?
Jun711
34

Puedes usar el método de traducción .

s.translate(None, '!.;,')
Praveen Gollakota
fuente
16
''.join(c for c in myString if not c in badTokens)
ninjagecko
fuente
Útil en casos similares no basados ​​en caracteres y cadenas +1
Wolf
12

Si está utilizando python3 y está buscando eltranslate solución, la función se cambió y ahora toma 1 parámetro en lugar de 2.

Ese parámetro es una tabla (puede ser un diccionario) donde cada clave es el ordinal Unicode (int) del carácter a buscar y el valor es el reemplazo (puede ser un ordinal Unicode o una cadena para asignar la clave).

Aquí hay un ejemplo de uso:

>>> list = [',', '!', '.', ';']
>>> s = "This is, my! str,ing."
>>> s.translate({ord(x): '' for x in list})
'This is my string'
Dekel
fuente
8

Otro enfoque usando regex:

''.join(re.split(r'[.;!?,]', s))
alan
fuente
7

¿Por qué no un simple bucle?

for i in replace_list:
    string = string.replace(i, '')

Además, evite nombrar listas 'lista'. Anula la función incorporada list.

aIKid
fuente
6

podrías usar algo como esto

def replace_all(text, dic):
  for i, j in dic.iteritems():
    text = text.replace(i, j)
  return text

Este código no es mío y viene de aquí, es un gran artículo y discute en profundidad haciendo esto

honor cristalino
fuente
3

También un tema interesante sobre la eliminación de acento UTF-8 forma una cadena que convierte char a su char estándar no acentuado:

¿Cuál es la mejor manera de eliminar acentos en una cadena Unicode de Python?

extracto de código del tema:

import unicodedata

def remove_accents(input_str):
    nkfd_form = unicodedata.normalize('NFKD', input_str)
    return u"".join([c for c in nkfd_form if not unicodedata.combining(c)])
Sylvain
fuente
3

Quizás una forma más moderna y funcional de lograr lo que deseas:

>>> subj = 'A.B!C?'
>>> list = set([',', '!', '.', ';', '?'])
>>> filter(lambda x: x not in list, subj)
'ABC'

tenga en cuenta que para este propósito en particular es una exageración, pero una vez que necesita condiciones más complejas, el filtro es útil

amotinado
fuente
También tenga en cuenta que esto se puede hacer fácilmente con las comprensiones de listas, que en mi opinión es mucho más pitónico.
Disturbó el
3

manera simple,

import re
str = 'this is string !    >><< (foo---> bar) @-tuna-#   sandwich-%-is-$-* good'

// condense multiple empty spaces into 1
str = ' '.join(str.split()

// replace empty space with dash
str = str.replace(" ","-")

// take out any char that matches regex
str = re.sub('[!@#$%^&*()_+<>]', '', str)

salida:

this-is-string--foo----bar--tuna---sandwich--is---good

perfecto25
fuente
1

¿Qué tal esto?

reduce(lambda x,y : x.replace(y,"") ,[',', '!', '.', ';'],";Test , ,  !Stri!ng ..")
Akshay Hazari
fuente
1

Creo que esto es bastante simple y lo hará!

list = [",",",","!",";",":"] #the list goes on.....

theString = "dlkaj;lkdjf'adklfaj;lsd'fa'dfj;alkdjf" #is an example string;
newString="" #the unwanted character free string
for i in range(len(TheString)):
    if theString[i] in list:
        newString += "" #concatenate an empty string.
    else:
        newString += theString[i]

Esta es una manera de hacerlo. Pero si está cansado de mantener una lista de caracteres que desea eliminar, puede hacerlo utilizando el número de orden de las cadenas por las que itera. El número de orden es el valor ASCII de ese carácter. el número ascii para 0 como un carácter es 48 y el número ascii para z minúscula es 122, entonces:

theString = "lkdsjf;alkd8a'asdjf;lkaheoialkdjf;ad"
newString = ""
for i in range(len(theString)):
     if ord(theString[i]) < 48 or ord(theString[i]) > 122: #ord() => ascii num.
         newString += ""
     else:
        newString += theString[i]
Hiskel Kelemework
fuente
0

En estos días me estoy sumergiendo en el esquema, y ​​ahora creo que soy bueno recurriendo y evaluando. JAJAJA. Solo comparte algunas formas nuevas:

primero, evalúalo

print eval('string%s' % (''.join(['.replace("%s","")'%i for i in replace_list])))

segundo, recurse

def repn(string,replace_list):
    if replace_list==[]:
        return string
    else:
        return repn(string.replace(replace_list.pop(),""),replace_list)

print repn(string,replace_list)

Oye, no desestimes. Solo quiero compartir alguna idea nueva.

tcpiper
fuente
0

Estoy pensando en una solución para esto. Primero, haría la entrada de cadena como una lista. Luego reemplazaría los elementos de la lista. Luego, mediante el uso del comando join, devolveré la lista como una cadena. El código puede ser así:

def the_replacer(text):
    test = []    
    for m in range(len(text)):
        test.append(text[m])
        if test[m]==','\
        or test[m]=='!'\
        or test[m]=='.'\
        or test[m]=='\''\
        or test[m]==';':
    #....
            test[n]=''
    return ''.join(test)

Esto eliminaría cualquier cosa de la cadena. ¿Qué piensas sobre eso?

Sheikh Ahmad Shah
fuente
0

Aquí hay un more_itertoolsenfoque:

import more_itertools as mit


s = "A.B!C?D_E@F#"
blacklist = ".!?_@#"

"".join(mit.flatten(mit.split_at(s, pred=lambda x: x in set(blacklist))))
# 'ABCDEF'

Aquí dividimos los elementos encontrados en el blacklist, aplanamos los resultados y unimos la cadena.

pylang
fuente
0

Python 3, implementación de comprensión de lista de una sola línea.

from string import ascii_lowercase # 'abcdefghijklmnopqrstuvwxyz'
def remove_chars(input_string, removable):
  return ''.join([_ for _ in input_string if _ not in removable])

print(remove_chars(input_string="Stack Overflow", removable=ascii_lowercase))
>>> 'S O'
John Forbes
fuente
0

Eliminar *%,&@! desde abajo cadena:

s = "this is my string,  and i will * remove * these ** %% "
new_string = s.translate(s.maketrans('','','*%,&@!'))
print(new_string)

# output: this is my string  and i will  remove  these  
Biplob Das
fuente