Usuwanie listy znaków w ciągu


217

Chcę usunąć znaki w ciągu znaków w pythonie:

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

Ale mam wiele postaci, które muszę usunąć. Myślałem o liście

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

Ale jak mogę użyć listdo zastąpienia znaków w string?


6
Zobacz stackoverflow.com/questions/1919096/... dla różnych rozwiązań i miłego porównania.
Martijn de Milliano

Szkoda, że ​​Python (o którym mówi się, że ma dołączone baterie) nie obsługuje tego przypadku użycia po wyjęciu z pudełka. Robi to funkcja str_replace PHP - możesz przekazać tablicę jako pierwszy argument, a łańcuch jako drugi ( php.net/manual/pl/function.str-replace.php ).
JustAC0der

Odpowiedzi:


265

Jeśli używasz Python2, a twoje dane wejściowe są ciągami (nie kodami Unicode), absolutnie najlepszą metodą jest str.translate:

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

W przeciwnym razie należy rozważyć następujące opcje:

A. Iteruj znak po znaku char, pomiń niechciane znaki i joinwynikową listę:

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

(Uwaga: wersja generatora ''.join(c for c ...) będzie mniej wydajna).

B. Utwórz w locie wyrażenie regularne re.subz pustym ciągiem znaków:

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

( re.escapezapewnia, że ​​znaki takie jak ^lub] nie złamie wyrażenie regularne).

C. Użyj wariantu mapowaniatranslate :

>>> 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'

Pełny kod testowy i czasy:

#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)

Wyniki:

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

(Na marginesie, liczba ta remove_chars_translate_bytesmoże dać nam wskazówkę, dlaczego przemysł tak niechętnie stosuje Unicode przez tak długi czas).


1
Druga metoda powoduje błąd TypeError: translate() takes exactly one argument (2 given). Najwyraźniej argument stanowi argument.
antonavy

@antonavy - 2. rozwiązanie działa - ale tylko ciąg znaków nie jest Unicode (dla którego konieczne jest inne tłumaczenie ())
FuzzyAmi

112

Możesz użyć str.translate():

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

Przykład:

>>> s = "asjo,fdjk;djaso,oio!kod.kjods;dkps"
>>> s.translate(None, ",!.;")
'asjofdjkdjasooiokodkjodsdkps'

19
@ thg435: Nikt o to nie prosił, ale w każdym razie:s.translate(dict.fromkeys(map(ord, u",!.;")))
Sven Marnach

2
Ta jednoczesna odpowiedź (i @ PraveenGollakota) jest dokładnie tym, o co poprosiła @Laura i powinna być preferowaną odpowiedzią.
płyty grzewcze

7
dlaczego python3: TypeError: translate () bierze dokładnie jeden argument (podano 2)
Gank

2
@Gank: unicode.translate()Metoda ma inne parametry niż str.translate()metoda. Użyj wariantu w powyższym komentarzu dla obiektów Unicode.
Sven Marnach,

@ SvvenMarnach co to jest mapa (ord, u ",!.;"))? a czy reprezentujesz Unicode?
Jun711,


16
''.join(c for c in myString if not c in badTokens)

Przydatny w podobnych przypadkach nie opartych na znakach i ciągach +1
Wolf

12

Jeśli używasz Python3 i szukasz translaterozwiązania - funkcja została zmieniona i teraz przyjmuje 1 parametr zamiast 2.

Ten parametr jest tabelą (może być słownikiem), w której każdy klucz jest liczbą porządkową Unicode (int) znaku do znalezienia, a wartością jest zamiennik (może być liczbą porządkową Unicode lub ciągiem znaków, na który ma zostać odwzorowany klucz).

Oto przykład użycia:

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

8

Inne podejście z użyciem wyrażenia regularnego:

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

7

Dlaczego nie prosta pętla?

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

Unikaj także listy nazwisk. Zastępuje wbudowaną funkcję list.


6

możesz użyć czegoś takiego

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

Ten kod nie jest moim własnym i pochodzi stąd świetny artykuł i szczegółowo to robię



3

Być może bardziej nowoczesny i funkcjonalny sposób na osiągnięcie tego, co chcesz:

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

należy pamiętać, że w tym konkretnym celu jest to dość przesada, ale gdy potrzebujesz bardziej złożonych warunków, przydatny jest filtr


Zauważ też, że można to równie łatwo zrobić za pomocą list, co jest moim zdaniem znacznie bardziej pytoniczne.
zamieszki

3

prosta droga,

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)

wynik:

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


1

Co powiesz na to - jedna wkładka.

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

1

myślę, że jest to dość proste i wystarczy!

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]

to jeden ze sposobów, aby to zrobić. Ale jeśli masz dość utrzymywania listy znaków, które chcesz usunąć, możesz to zrobić, korzystając z numeru porządkowego ciągów, które iterujesz. numer zamówienia jest wartością ascii tego znaku. liczba ascii dla 0 jako char wynosi 48, a liczba ascii dla małych liter z wynosi 122, więc:

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]

0

Obecnie nurkuję w schemacie, a teraz myślę, że jestem dobry w rekursywności i ewaluacji. HAHAHA. Po prostu udostępnij kilka nowych sposobów:

po pierwsze, sprawdź to

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

po drugie, powtórz to

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)

Hej, nie głosuj za głosem. Chcę tylko podzielić się nowym pomysłem.


0

Myślę o rozwiązaniu tego problemu. Najpierw wprowadzę ciąg znaków jako listę. Następnie zastąpiłbym pozycje z listy. Następnie za pomocą polecenia Join zwrócę listę jako ciąg znaków. Kod może wyglądać tak:

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)

Spowoduje to usunięcie czegokolwiek z ciągu. Co myślicie o tym?


0

Oto more_itertoolspodejście:

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'

Tutaj dzielimy się na przedmioty znalezione w blacklist, spłaszczamy wyniki i łączymy ciąg.


0

Python 3, implementacja rozumienia listy pojedynczej linii.

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'

0

Usuń *% i @! z poniżej ciągu:

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  
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.