Python, usuń wszystkie znaki inne niż alfabetyczne z łańcucha


90

Piszę program do liczenia słów MapReduce w języku python. Problem polega na tym, że w danych jest wiele znaków innych niż alfabet, znalazłem ten post Usuwanie wszystkiego oprócz znaków alfanumerycznych z łańcucha w Pythonie, który pokazuje ładne rozwiązanie za pomocą wyrażenia regularnego, ale nie jestem pewien, jak to zaimplementować

def mapfn(k, v):
    print v
    import re, string 
    pattern = re.compile('[\W_]+')
    v = pattern.match(v)
    print v
    for w in v.split():
        yield w, 1

Obawiam się, że nie jestem pewien, jak używać biblioteki, rea nawet wyrażenia regularnego w tym celu. Nie jestem pewien, jak vpoprawnie zastosować wzorzec wyrażenia regularnego do przychodzącego ciągu (wiersza książki), aby pobrać nowy wiersz bez żadnych znaków niealfanumerycznych.

Propozycje?


vto cała linia książki (szczególnie moby dick), idę słowo po słowie, a nie znak po znaku. Dlatego niektóre słowa mogą mieć na końcu „,”, więc „zniewaga” nie pokrywa się z „zniewagą”.
KDecker


Lolx - czy wykonałeś to samo ćwiczenie domowe przed rozmową kwalifikacyjną co ja? Znajdź 50 najczęściej używanych słów w Moby Dick i podaj ich częstotliwość. Zrobiłem to w C ++, IIRC
Mawg mówi, że przywróć Monikę

1
@Mawg To było ćwiczenie z mojej klasy „Cloud Computing”.
KDecker

Odpowiedzi:


127

Posługiwać się re.sub

import re

regex = re.compile('[^a-zA-Z]')
#First parameter is the replacement, second parameter is your input string
regex.sub('', 'ab3d*E')
#Out: 'abdE'

Alternatywnie, jeśli chcesz usunąć tylko określony zestaw znaków (jako apostrof może być w porządku w twoim wejściu ...)

regex = re.compile('[,\.!?]') #etc.

Hmm, mogę to całkiem wyśledzić, ale co ze wzorem usuwania wszystkich znaków niealfanumerycznych z wyjątkiem spacji?
KDecker

1
Po prostu dodaj spację do swojej klasy kolekcji. czyli ^a-zA-Z zamiast tylko^a-zA-Z
limasxgoesto0

Chyba że martwisz się także nowymi liniami, w takim przypadku a-zA-Z \n. Próbuję znaleźć wyrażenie regularne, które połączyłoby oba te elementy w jedno, ale używając \wlub \Wnie zapewniając mi pożądanego zachowania. Możesz po prostu dodać, \njeśli tak jest.
limasxgoesto0

Ahh, znak nowej linii. Na tym polegają moje problemy, porównywałem swoje wyniki z podanymi wynikami i nadal byłem wyłączony. Myślę, że to mój problem! Dzięki // Hmm, wypróbowałem to z nowym znakiem z tymi samymi wynikami, myślę, że brakuje mi innego .. // Duhhh ... Wielkie i małe litery ... // Dzięki za całą pomoc, teraz działa idealnie!
KDecker

48

Jeśli wolisz nie używać wyrażenia regularnego, możesz spróbować

''.join([i for i in s if i.isalpha()])

jak mam się do tego przyłączyć? z „” .join?
print

Wow, właśnie tego szukałem. Uwzględnia to kanji, hiragana, katakana itp. kudos
root163

34

Możesz użyć funkcji re.sub (), aby usunąć te znaki:

>>> import re
>>> re.sub("[^a-zA-Z]+", "", "ABC12abc345def")
'ABCabcdef'

re.sub (DOPASUJ WZÓR, ZAMIEŃ ŁAŃCUCH, ŁAŃCUCH DO SZUKANIA)

  • "[^a-zA-Z]+" - poszukaj dowolnej grupy znaków, które NIE są a-zA-z.
  • "" - Zastąp dopasowane znaki znakiem „”

Pamiętaj, że usunie to również litery akcentowane: ãâàáéèçõ itp.
Brad Ahrens

19

Próbować:

s = ''.join(filter(str.isalnum, s))

Spowoduje to pobranie każdego znaku z łańcucha, zachowanie tylko znaków alfanumerycznych i zbudowanie z nich łańcucha.


1
Ta odpowiedź może zawierać dużo więcej wyjaśnień i linków do odpowiedniej dokumentacji.
pdoherty926

4

Najszybszą metodą jest regex

#Try with regex first
t0 = timeit.timeit("""
s = r2.sub('', st)

""", setup = """
import re
r2 = re.compile(r'[^a-zA-Z0-9]', re.MULTILINE)
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""", number = 1000000)
print(t0)

#Try with join method on filter
t0 = timeit.timeit("""
s = ''.join(filter(str.isalnum, st))

""", setup = """
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""",
number = 1000000)
print(t0)

#Try with only join
t0 = timeit.timeit("""
s = ''.join(c for c in st if c.isalnum())

""", setup = """
st = 'abcdefghijklmnopqrstuvwxyz123456789!@#$%^&*()-=_+'
""", number = 1000000)
print(t0)


2.6002226710006653 Method 1 Regex
5.739747313000407 Method 2 Filter + Join
6.540099570000166 Method 3 Join

0

Zaleca się użycie modułu PyPi regex, jeśli planujesz dopasować określone klasy właściwości Unicode. Ta biblioteka okazała się również bardziej stabilna, szczególnie w przypadku dużych tekstów i zapewnia spójne wyniki w różnych wersjach języka Python. Wszystko, co musisz zrobić, to dbać o jego aktualność.

Jeśli ją zainstalujesz (używając pip intall regexlub pip3 install regex), możesz użyć

import regex
print ( regex.sub(r'\P{L}+', '', 'ABCŁąć1-2!Абв3§4“5def”') )
// => ABCŁąćАбвdef

aby usunąć wszystkie fragmenty 1 lub więcej znaków innych niż litery Unicode z text. Zobacz demo online Pythona . Możesz również użyć, "".join(regex.findall(r'\p{L}+', 'ABCŁąć1-2!Абв3§4“5def”'))aby uzyskać ten sam wynik.

W Pythonie re, aby dopasować dowolną literę Unicode, można użyć [^\W\d_]konstrukcji ( Dopasować dowolną literę Unicode? ).

Tak więc, aby usunąć wszystkie znaki niebędące literami, możesz dopasować wszystkie litery i dołączyć do wyników:

result = "".join(re.findall(r'[^\W\d_]', text))

Lub usuń wszystkie znaki inne niż dopasowane do [^\W\d_]:

result = re.sub(r'([^\W\d_])|.', r'\1', text, re.DOTALL)

Zobacz demo wyrażenia regularnego online . Jednak możesz uzyskać niespójne wyniki w różnych wersjach Pythona, ponieważ standard Unicode ewoluuje, a zestaw dopasowanych znaków \wbędzie zależał od wersji Pythona. Zaleca się korzystanie z regexbiblioteki PyPi, aby uzyskać spójne wyniki.

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.