Próbuję usunąć określone znaki z ciągu przy użyciu Pythona. Tego właśnie używam kodu. Niestety wydaje się, że nic nie robi na łańcuch.
for char in line:
if char in " ?.!/;:":
line.replace(char,'')
Jak to zrobić poprawnie?
Próbuję usunąć określone znaki z ciągu przy użyciu Pythona. Tego właśnie używam kodu. Niestety wydaje się, że nic nie robi na łańcuch.
for char in line:
if char in " ?.!/;:":
line.replace(char,'')
Jak to zrobić poprawnie?
Odpowiedzi:
Ciągi w Pythonie są niezmienne (nie można ich zmienić). Z tego powodu efektem line.replace(...)
jest po prostu utworzenie nowego ciągu, a nie zmiana starego. Musisz ponownie powiązać (przypisać) line
, aby zmienna przyjmowała nową wartość, a znaki zostały usunięte.
Ponadto sposób, w jaki to robisz, będzie względnie powolny. Może to być nieco mylące dla doświadczonych pythonatorów, którzy zobaczą podwójnie zagnieżdżoną strukturę i pomyślą przez chwilę, że dzieje się coś bardziej skomplikowanego.
Począwszy od Python 2.6 i nowszych wersji Python 2.x *, możesz zamiast tego użyć str.translate
(ale czytaj dalej o różnicach w Python 3):
line = line.translate(None, '!@#$')
lub zamiana wyrażeń regularnych na re.sub
import re
line = re.sub('[!@#$]', '', line)
Znaki w nawiasach stanowią klasę znaków . Wszelkie znaki, line
które należą do tej klasy, są zastępowane drugim parametrem sub
: pusty ciąg znaków.
W Pythonie 3 ciągi znaków są Unicode. Musisz przetłumaczyć trochę inaczej. kevpie wspomina o tym w komentarzu do jednej z odpowiedzi i jest to odnotowane w dokumentacji dlastr.translate
.
Podczas wywoływania translate
metody ciągu Unicode nie można przekazać drugiego parametru, którego użyliśmy powyżej. Nie możesz również przekazać None
jako pierwszego parametru. Zamiast tego przekazujesz tabelę tłumaczeń (zwykle słownik) jako jedyny parametr. Ta tabela odwzorowuje wartości porządkowe znaków (tj. Wynik ich wzywania ord
) na wartości porządkowe znaków, które powinny je zastąpić lub - co dla nas przydatne - None
aby wskazać, że należy je usunąć.
Aby wykonać powyższy taniec za pomocą łańcucha Unicode, nazwałbyś coś takiego
translation_table = dict.fromkeys(map(ord, '!@#$'), None)
unicode_line = unicode_line.translate(translation_table)
Tutaj dict.fromkeys
i map
służą do zwięzłego wygenerowania słownika zawierającego
{ord('!'): None, ord('@'): None, ...}
Jeszcze prościej, jak mówi inna odpowiedź , utwórz tabelę tłumaczeń:
unicode_line = unicode_line.translate({ord(c): None for c in '!@#$'})
Lub utwórz tę samą tabelę tłumaczeń za pomocą str.maketrans
:
unicode_line = unicode_line.translate(str.maketrans('', '', '!@#$'))
* w celu zapewnienia zgodności z wcześniejszymi pythonami możesz utworzyć tabelę tłumaczeń „null”, która będzie przekazywana zamiast None
:
import string
line = line.translate(string.maketrans('', ''), '!@#$')
Tutaj string.maketrans
służy do utworzenia tabeli translacji , która jest tylko ciągiem zawierającym znaki o wartościach porządkowych od 0 do 255.
line.translate
pobiera tylko jeden argument i pierwsze rozwiązanie nie zadziała
line.translate({ord(i):None for i in '!@#$'})
"'"
dla zestawu znaków.
notes = notes.translate({ord(i):None for i in '\"\''})
unicode_line.translate(str.maketrans('', '', '!@#$'))
. Lubunicode_line.translate(dict.fromkeys(map(ord, '!@#$')))
Czy brakuje mi tutaj sensu, czy jest to po prostu:
string = "ab1cd1ef"
string = string.replace("1","")
print string
# result: "abcdef"
Umieść w pętli:
a = "a!b@c#d$"
b = "!@#$"
for char in b:
a = a.replace(char,"")
print a
# result: "abcd"
for char in b: a=a.replace(char,"")
string=string.replace("1","")
zamiast. W pewnym sensie powiedziałeś to w części z pętli, ale większość ludzi nie przeczyta tak daleko w twojej odpowiedzi, dopóki nie zaczną majstrować przy kodzie, aby uzyskać tak proste pytanie.
>>> line = "abc#@!?efg12;:?"
>>> ''.join( c for c in line if c not in '?:!/;' )
'abc#@efg12'
blacklist = set('?:!/;')
a następnie''.join(c for c in line if c not in blacklist)
re.sub
regularną ekspresją jak w Pythonie 3.5re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)
>>> import re
>>> line = 'Q: Do I write ;/.??? No!!!'
>>> re.sub('\ |\?|\.|\!|\/|\;|\:', '', line)
'QDoIwriteNo'
W wyrażeniach regularnych (regex) |
jest logicznym OR i \
ucieka przed spacjami i znakami specjalnymi, które mogą być rzeczywistymi komendami regex. Natomiast sub
oznacza podstawienie, w tym przypadku pusty ciąg ''
.
W przypadku odwrotnego wymogu dopuszczania tylko niektórych znaków w ciągu można użyć wyrażeń regularnych z operatorem zbioru dopełniacza [^ABCabc]
. Na przykład, aby usunąć wszystko oprócz liter ascii, cyfr i łącznika:
>>> import string
>>> import re
>>>
>>> phrase = ' There were "nine" (9) chick-peas in my pocket!!! '
>>> allow = string.letters + string.digits + '-'
>>> re.sub('[^%s]' % allow, '', phrase)
'Therewerenine9chick-peasinmypocket'
Z dokumentacji wyrażeń regularnych Pythona :
Znaki spoza zakresu można dopasować, uzupełniając zestaw. Jeśli pierwszym znakiem zestawu jest
'^'
, wszystkie znaki, których nie ma w zestawie, zostaną dopasowane. Na przykład[^5]
dopasuje dowolny znak oprócz „5” i[^^]
dopasuje dowolny znak oprócz'^'
.^
nie ma specjalnego znaczenia, jeśli nie jest to pierwszy znak w zestawie.
Pytający prawie go miał. Jak większość rzeczy w Pythonie, odpowiedź jest prostsza niż myślisz.
>>> line = "H E?.LL!/;O:: "
>>> for char in ' ?.!/;:':
... line = line.replace(char,'')
...
>>> print line
HELLO
Nie musisz wykonywać zagnieżdżonej pętli if / for, ale musisz sprawdzić każdy znak osobno.
line = line.translate(None, " ?.!/;:")
>>> s = 'a1b2c3'
>>> ''.join(c for c in s if c not in '123')
'abc'
Ciągi są niezmienne w Pythonie. replace
Metoda zwraca nowy łańcuch po wymianie. Próbować:
for char in line:
if char in " ?.!/;:":
line = line.replace(char,'')
line
.
Byłem zaskoczony, że nikt jeszcze nie zalecił używania wbudowanej funkcji filtra .
import operator
import string # only for the example you could use a custom string
s = "1212edjaq"
Powiedzmy, że chcemy odfiltrować wszystko, co nie jest liczbą. Użycie wbudowanej metody filtrowania „... jest równoważne wyrażeniu generatora (element dla elementu w iterowalnym, jeśli funkcja (element))” [ Wbudowane Python 3: Filtr ]
sList = list(s)
intsList = list(string.digits)
obj = filter(lambda x: operator.contains(intsList, x), sList)))
W Pythonie 3 to zwraca
>> <filter object @ hex>
Aby uzyskać wydrukowany ciąg,
nums = "".join(list(obj))
print(nums)
>> "1212"
Nie jestem pewien, jak filtrować plasuje się pod względem wydajności, ale dobrze jest wiedzieć, jak korzystać z niego podczas wykonywania list i tym podobne.
AKTUALIZACJA
Logicznie, ponieważ filtr działa, możesz również użyć analizy list i z tego, co przeczytałem, powinna być bardziej wydajna, ponieważ lambdas są menedżerami funduszy hedgingowych z Wall Street w świecie funkcji programistycznych. Kolejnym plusem jest to, że jest to jeden liniowiec, który nie wymaga żadnego importu. Na przykład, używając tego samego ciągu „s” zdefiniowanego powyżej,
num = "".join([i for i in s if i.isdigit()])
Otóż to. Zwrotem będzie ciąg wszystkich znaków, które są cyframi w oryginalnym ciągu.
Jeśli masz określoną listę akceptowalnych / niedopuszczalnych znaków, musisz tylko dostosować część „jeśli” w zrozumieniu listy.
target_chars = "".join([i for i in s if i in some_list])
lub alternatywnie
target_chars = "".join([i for i in s if i not in some_list])
operator.contains
jeśli lambda
mimo to używasz . lambda x: operator.contains(intsList, x)
należy przeliterować lambda x: x in intsList
, lub jeśli próbujesz uzyskać test na poziomie C, intsList.__contains__
(wcale nie lambda
).
Używając filter
, potrzebujesz tylko jednej linii
line = filter(lambda char: char not in " ?.!/;:", line)
To traktuje ciąg jako iterowalny i sprawdza każdy znak, jeśli lambda
zwraca True
:
>>> help(filter) Help on built-in function filter in module __builtin__: filter(...) filter(function or None, sequence) -> list, tuple, or string Return those items of sequence for which function(item) is true. If function is None, return the items that are true. If sequence is a tuple or string, return the same type, else return a list.
Oto kilka możliwych sposobów realizacji tego zadania:
def attempt1(string):
return "".join([v for v in string if v not in ("a", "e", "i", "o", "u")])
def attempt2(string):
for v in ("a", "e", "i", "o", "u"):
string = string.replace(v, "")
return string
def attempt3(string):
import re
for v in ("a", "e", "i", "o", "u"):
string = re.sub(v, "", string)
return string
def attempt4(string):
return string.replace("a", "").replace("e", "").replace("i", "").replace("o", "").replace("u", "")
for attempt in [attempt1, attempt2, attempt3, attempt4]:
print(attempt("murcielago"))
PS: Zamiast tego używając „?.! / ;:” przykłady używają samogłosek… i tak, „murcielago” to hiszpańskie słowo oznaczające nietoperz… zabawne słowo, ponieważ zawiera wszystkie samogłoski :)
PS2: Jeśli interesuje Cię wydajność, możesz zmierzyć te próby za pomocą prostego kodu, takiego jak:
import timeit
K = 1000000
for i in range(1,5):
t = timeit.Timer(
f"attempt{i}('murcielago')",
setup=f"from __main__ import attempt{i}"
).repeat(1, K)
print(f"attempt{i}",min(t))
W moim pudełku dostaniesz:
attempt1 2.2334518376057244
attempt2 1.8806643818474513
attempt3 7.214925774955572
attempt4 1.7271184513757465
Wygląda na to, że próba4 jest najszybsza dla tego konkretnego wejścia.
list
się attempt1
i krotka może być zapisane do "aeiou"
na litość prostota (usuwanie [
i ]
włączy się do generatora bez tworzenia listy). Tworzysz mnóstwo wyrzucanych łańcuchów pośrednich attemt2
, używasz wielu aplikacji wyrażenia regularnego, w attempt3
których możesz użyć r'[aeiou]'
w jednym przejściu. każdy z nich ma wady - miło jest widzieć różne sposoby robienia rzeczy, ale proszę również naprawić je, aby były dobre
Oto moja wersja zgodna z Python 2/3. Od czasu zmiany interfejsu API tłumaczenia.
def remove(str_, chars):
"""Removes each char in `chars` from `str_`.
Args:
str_: String to remove characters from
chars: String of to-be removed characters
Returns:
A copy of str_ with `chars` removed
Example:
remove("What?!?: darn;", " ?.!:;") => 'Whatdarn'
"""
try:
# Python2.x
return str_.translate(None, chars)
except TypeError:
# Python 3.x
table = {ord(char): None for char in chars}
return str_.translate(table)
dict.fromkeys(map(ord, '!@#$'))
stworzyć mapę.
map
jest ogólnie mniej czytelny niż zrozumienie listy / dict / set / generatora. Tak bardzo, że Guido chciał go usunąć z języka . Używanie fromkeys
jest również nieco sprytne i wymaga sprawdzenia dokumentacji.
str.maketrans('', '', chars)
który obsługuje ord
konwersję i dict
budowę za jednym razem (nie wspominając o bardziej oczywistym zamiarze, ponieważ jest przeznaczony do parowania str.translate
).
#!/usr/bin/python
import re
strs = "how^ much for{} the maple syrup? $20.99? That's[] ricidulous!!!"
print strs
nstr = re.sub(r'[?|$|.|!|a|b]',r' ',strs)#i have taken special character to remove but any #character can be added here
print nstr
nestr = re.sub(r'[^a-zA-Z0-9 ]',r'',nstr)#for removing special character
print nestr
'
za ciąg. docs.python.org/2/library/re.html
Co powiesz na to:
def text_cleanup(text):
new = ""
for i in text:
if i not in " ?.!/;:":
new += i
return new
Możesz także użyć funkcji w celu zastąpienia innego rodzaju wyrażeń regularnych lub innego wzorca za pomocą listy. Dzięki temu możesz mieszać wyrażenia regularne, klasę znaków i naprawdę podstawowy wzorzec tekstu. Jest to bardzo przydatne, gdy trzeba zastąpić wiele elementów, takich jak HTML.
* Uwaga: działa z Python 3.x
import re # Regular expression library
def string_cleanup(x, notwanted):
for item in notwanted:
x = re.sub(item, '', x)
return x
line = "<title>My example: <strong>A text %very% $clean!!</strong></title>"
print("Uncleaned: ", line)
# Get rid of html elements
html_elements = ["<title>", "</title>", "<strong>", "</strong>"]
line = string_cleanup(line, html_elements)
print("1st clean: ", line)
# Get rid of special characters
special_chars = ["[!@#$]", "%"]
line = string_cleanup(line, special_chars)
print("2nd clean: ", line)
W funkcji string_cleanup bierze twój łańcuch x, a lista niepotrzebna jako argument. Dla każdego elementu na tej liście elementów lub wzoru, jeśli potrzebny będzie zamiennik, zostanie to zrobione.
Wyjście:
Uncleaned: <title>My example: <strong>A text %very% $clean!!</strong></title>
1st clean: My example: A text %very% $clean!!
2nd clean: My example: A text very clean
Moja metoda, której użyłabym, prawdopodobnie nie działałaby tak skutecznie, ale jest niezwykle prosta. Mogę usunąć wiele znaków w różnych pozycjach jednocześnie, korzystając z krojenia i formatowania. Oto przykład:
words = "things"
removed = "%s%s" % (words[:3], words[-1:])
Spowoduje to, że słowo „usunięte” będzie zawierać słowo „to”.
Formatowanie może być bardzo pomocne przy drukowaniu zmiennych w połowie ciągu wydruku. Może wstawić dowolny typ danych, używając %, po którym następuje typ danych zmiennej; wszystkie typy danych mogą używać % s , zmiennoprzecinkowe (inaczej dziesiętne), a liczby całkowite mogą używać % d .
Krojenie może być użyte do zawiłej kontroli nad łańcuchami. Kiedy wstawię słowa [: 3] , pozwala mi wybrać wszystkie znaki w ciągu od początku (dwukropek znajduje się przed liczbą, będzie to oznaczać „od początku do”) do czwartego znaku (zawiera czwarty znak postać). Powód 3 jest równy do czwartej pozycji, ponieważ Python zaczyna się od 0. Następnie, gdy wstawię słowo [-1:] , oznacza to, że na końcu znajduje się 2. ostatni znak (dwukropek znajduje się za liczbą). Ustawienie -1 spowoduje, że Python będzie liczony od ostatniego znaku, a nie od pierwszego. Ponownie Python rozpocznie się od 0. Więc słowo [-1:] zasadzie oznacza „od drugiego ostatniego znaku do końca ciągu.
Tak więc, odcinając postacie przed postacią, którą chcę usunąć, oraz postacie po i łącząc je ze sobą, mogę usunąć niechcianą postać. Pomyśl o tym jak o kiełbasie. Na środku jest brudno, więc chcę się go pozbyć. Po prostu odcinam dwa końce, które chcę, a następnie łączę je bez niechcianej części pośrodku.
Jeśli chcę usunąć wiele kolejnych znaków, po prostu przesuwam liczby w [] (część krojenia). Lub jeśli chcę usunąć wiele postaci z różnych pozycji, mogę po prostu połączyć wiele plasterków jednocześnie.
Przykłady:
words = "control"
removed = "%s%s" % (words[:2], words[-2:])
usunięto równa się „cool”.
words = "impacts"
removed = "%s%s%s" % (words[1], words[3:5], words[-1])
usunięto równa się „macs”.
W tym przypadku [3: 5] oznacza znak na pozycji 3 poprzez znak na pozycji 5 (z wyłączeniem znaku na końcowej pozycji).
Pamiętaj, że Python zaczyna odliczanie od 0 , więc musisz również.
Spróbuj tego:
def rm_char(original_str, need2rm):
''' Remove charecters in "need2rm" from "original_str" '''
return original_str.translate(str.maketrans('','',need2rm))
Ta metoda działa dobrze w Pythonie 3.5.2
Możesz użyć zamiany wyrażeń regularnych w module re. Użycie wyrażenia ^ pozwala wybrać dokładnie to, co chcesz z łańcucha.
import re
text = "This is absurd!"
text = re.sub("[^a-zA-Z]","",text) # Keeps only Alphabets
print(text)
Wynikiem tego będzie „Thisisabsurd”. Pojawią się tylko rzeczy określone po symbolu ^.
Metoda ciągu replace
nie modyfikuje oryginalnego ciągu. Pozostawia oryginał sam i zwraca zmodyfikowaną kopię.
To, czego chcesz, to: line = line.replace(char,'')
def replace_all(line, )for char in line:
if char in " ?.!/;:":
line = line.replace(char,'')
return line
Jednak tworzenie nowego ciągu za każdym razem, gdy znak jest usuwany, jest bardzo nieefektywne. Zamiast tego polecam następujące:
def replace_all(line, baddies, *):
"""
The following is documentation on how to use the class,
without reference to the implementation details:
For implementation notes, please see comments begining with `#`
in the source file.
[*crickets chirp*]
"""
is_bad = lambda ch, baddies=baddies: return ch in baddies
filter_baddies = lambda ch, *, is_bad=is_bad: "" if is_bad(ch) else ch
mahp = replace_all.map(filter_baddies, line)
return replace_all.join('', join(mahp))
# -------------------------------------------------
# WHY `baddies=baddies`?!?
# `is_bad=is_bad`
# -------------------------------------------------
# Default arguments to a lambda function are evaluated
# at the same time as when a lambda function is
# **defined**.
#
# global variables of a lambda function
# are evaluated when the lambda function is
# **called**
#
# The following prints "as yellow as snow"
#
# fleece_color = "white"
# little_lamb = lambda end: return "as " + fleece_color + end
#
# # sometime later...
#
# fleece_color = "yellow"
# print(little_lamb(" as snow"))
# --------------------------------------------------
replace_all.map = map
replace_all.join = str.join
możesz użyć zestawu
charlist = list(set(string.digits+string.ascii_uppercase) - set('10IO'))
return ''.join([random.SystemRandom().choice(charlist) for _ in range(passlen)])
# dla każdego pliku w katalogu, zmień nazwę pliku
file_list = os.listdir (r"D:\Dev\Python")
for file_name in file_list:
os.rename(file_name, re.sub(r'\d+','',file_name))
>>> # Character stripping
>>> a = '?abcd1234!!'
>>> t.lstrip('?')
'abcd1234!!'
>>> t.strip('?!')
'abcd1234'
filter
funkcji i wyrażenia lambda:filter(lambda ch: ch not in " ?.!/;:", line)
. Myślę, że dość zwięzłe i wydajne. Oczywiście zwraca nowy ciąg, któremu będziesz musiał przypisać nazwę.