Zmierzyłem wszystkie metody w bieżących odpowiedziach wraz z jedną dodatkową.
Z ciągiem wejściowym abc&def#ghii zastąpienie & -> \ & i # -> \ #, najszybszym sposobem było łańcucha razem zamienniki tak: text.replace('&', '\&').replace('#', '\#').
Czasy dla każdej funkcji:
a) 1000000 pętli, najlepiej 3: 1,47 μs na pętlę
b) 1000000 pętli, najlepiej 3: 1,51 μs na pętlę
c) 100000 pętli, najlepiej 3: 12,3 μs na pętlę
d) 100000 pętli, najlepiej 3: 12 μs na pętlę
e) 100000 pętli, najlepiej 3: 3,27 μs na pętlę
f) 1000000 pętli, najlepiej 3: 0,817 μs na pętlę
g) 100000 pętli, najlepiej 3: 3,64 μs na pętlę
h) 1000000 pętli, najlepiej 3: 0,927 μs na pętlę
i) 1000000 pętli, najlepiej 3: 0,814 μs na pętlę
Oto funkcje:
def a(text):
chars ="&#"for c in chars:
text = text.replace(c,"\\"+ c)def b(text):for ch in['&','#']:if ch in text:
text = text.replace(ch,"\\"+ch)import re
def c(text):
rx = re.compile('([&#])')
text = rx.sub(r'\\\1', text)
RX = re.compile('([&#])')def d(text):
text = RX.sub(r'\\\1', text)def mk_esc(esc_chars):returnlambda s:''.join(['\\'+ c if c in esc_chars else c for c in s])
esc = mk_esc('&#')def e(text):
esc(text)def f(text):
text = text.replace('&','\&').replace('#','\#')def g(text):
replacements ={"&":"\&","#":"\#"}
text ="".join([replacements.get(c, c)for c in text])def h(text):
text = text.replace('&', r'\&')
text = text.replace('#', r'\#')def i(text):
text = text.replace('&', r'\&').replace('#', r'\#')
Oto podobny kod, aby zrobić to samo, ale z większą ilością znaków do ucieczki (\ `* _ {}> # + -.! $):
def a(text):
chars ="\\`*_{}[]()>#+-.!$"for c in chars:
text = text.replace(c,"\\"+ c)def b(text):for ch in['\\','`','*','_','{','}','[',']','(',')','>','#','+','-','.','!','$','\'']:if ch in text:
text = text.replace(ch,"\\"+ch)import re
def c(text):
rx = re.compile('([&#])')
text = rx.sub(r'\\\1', text)
RX = re.compile('([\\`*_{}[]()>#+-.!$])')def d(text):
text = RX.sub(r'\\\1', text)def mk_esc(esc_chars):returnlambda s:''.join(['\\'+ c if c in esc_chars else c for c in s])
esc = mk_esc('\\`*_{}[]()>#+-.!$')def e(text):
esc(text)def f(text):
text = text.replace('\\','\\\\').replace('`','\`').replace('*','\*').replace('_','\_').replace('{','\{').replace('}','\}').replace('[','\[').replace(']','\]').replace('(','\(').replace(')','\)').replace('>','\>').replace('#','\#').replace('+','\+').replace('-','\-').replace('.','\.').replace('!','\!').replace('$','\$')def g(text):
replacements ={"\\":"\\\\","`":"\`","*":"\*","_":"\_","{":"\{","}":"\}","[":"\[","]":"\]","(":"\(",")":"\)",">":"\>","#":"\#","+":"\+","-":"\-",".":"\.","!":"\!","$":"\$",}
text ="".join([replacements.get(c, c)for c in text])def h(text):
text = text.replace('\\', r'\\')
text = text.replace('`', r'\`')
text = text.replace('*', r'\*')
text = text.replace('_', r'\_')
text = text.replace('{', r'\{')
text = text.replace('}', r'\}')
text = text.replace('[', r'\[')
text = text.replace(']', r'\]')
text = text.replace('(', r'\(')
text = text.replace(')', r'\)')
text = text.replace('>', r'\>')
text = text.replace('#', r'\#')
text = text.replace('+', r'\+')
text = text.replace('-', r'\-')
text = text.replace('.', r'\.')
text = text.replace('!', r'\!')
text = text.replace('$', r'\$')def i(text):
text = text.replace('\\', r'\\').replace('`', r'\`').replace('*', r'\*').replace('_', r'\_').replace('{', r'\{').replace('}', r'\}').replace('[', r'\[').replace(']', r'\]').replace('(', r'\(').replace(')', r'\)').replace('>', r'\>').replace('#', r'\#').replace('+', r'\+').replace('-', r'\-').replace('.', r'\.').replace('!', r'\!').replace('$', r'\$')
Oto wyniki dla tego samego ciągu wejściowego abc&def#ghi:
a) 100000 pętli, najlepiej 3: 6,72 μs na pętlę
b) 100000 pętli, najlepiej 3: 2,64 μs na pętlę
c) 100000 pętli, najlepiej 3: 11,9 μs na pętlę
d) 100000 pętli, najlepiej 3: 4,92 μs na pętlę
e) 100000 pętli, najlepiej 3: 2,96 μs na pętlę
f) 100000 pętli, najlepiej 3: 4,29 μs na pętlę
g) 100000 pętli, najlepiej 3: 4,68 μs na pętlę
h) 100000 pętli, najlepiej 3: 4,73 μs na pętlę
i) 100000 pętli, najlepiej 3: 4,24 μs na pętlę
I przy dłuższym ciągu wejściowym ( ## *Something* and [another] thing in a longer sentence with {more} things to replace$):
a) 100000 pętli, najlepiej 3: 7,59 μs na pętlę
b) 100000 pętli, najlepiej 3: 6,54 μs na pętlę
c) 100000 pętli, najlepiej 3: 16,9 μs na pętlę
d) 100000 pętli, najlepiej 3: 7,29 μs na pętlę
e) 100000 pętli, najlepiej 3: 12,2 μs na pętlę
f) 100000 pętli, najlepiej 3: 5,38 μs na pętlę
g) 10000 pętli, najlepiej 3: 21,7 μs na pętlę
h) 100000 pętli, najlepiej 3: 5,7 μs na pętlę
i) 100000 pętli, najlepiej 3: 5,13 μs na pętlę
Dodanie kilku wariantów:
def ab(text):for ch in['\\','`','*','_','{','}','[',']','(',')','>','#','+','-','.','!','$','\'']:
text = text.replace(ch,"\\"+ch)def ba(text):
chars ="\\`*_{}[]()>#+-.!$"for c in chars:if c in text:
text = text.replace(c,"\\"+ c)
Przy krótszym wejściu:
ab) 100000 pętli, najlepiej 3: 7,05 μs na pętlę
ba) 100000 pętli, najlepiej 3: 2,4 μs na pętlę
Przy dłuższym wejściu:
ab) 100000 pętli, najlepiej 3: 7,71 μs na pętlę
ba) 100000 pętli, najlepiej 3: 6,08 μs na pętlę
Więc baużyję dla czytelności i szybkości.
Uzupełnienie
Podpowiedzi hacck w komentarzach, jedna różnica między abi bajest if c in text:czek. Przetestujmy je pod kątem jeszcze dwóch wariantów:
def ab_with_check(text):for ch in['\\','`','*','_','{','}','[',']','(',')','>','#','+','-','.','!','$','\'']:if ch in text:
text = text.replace(ch,"\\"+ch)def ba_without_check(text):
chars ="\\`*_{}[]()>#+-.!$"for c in chars:
text = text.replace(c,"\\"+ c)
Czasy w μs na pętlę w Pythonie 2.7.14 i 3.6.3 i na innym komputerze niż wcześniejszy zestaw, więc nie można bezpośrednio porównać.
╭────────────╥──────┬───────────────┬──────┬──────────────────╮│Py, input ║ ab │ ab_with_check │ ba │ ba_without_check │╞════════════╬══════╪═══════════════╪══════╪══════════════════╡│Py2, short ║8.81│4.22│3.45│8.01││Py3, short ║5.54│1.34│1.46│5.34│├────────────╫──────┼───────────────┼──────┼──────────────────┤│Py2, long ║9.3│7.15│6.85│8.55││Py3, long ║7.43│4.38│4.41│7.02│└────────────╨──────┴───────────────┴──────┴──────────────────┘
Możemy stwierdzić, że:
Osoby z czekiem są nawet 4x szybsze niż osoby bez czeku
ab_with_checkjest nieco na czele w Pythonie 3, ale ba(z czekiem) ma większą przewagę w Pythonie 2
Jednak największą lekcją tutaj jest to, że Python 3 jest do 3 razy szybszy niż Python 2 ! Nie ma ogromnej różnicy między najwolniejszym w Pythonie 3 i najszybszym w Pythonie 2!
@haccks Nie jest to konieczne, ale jest 2-3 razy szybsze. Krótki łańcuch, z: 1.45 usec per loopi bez: 5.3 usec per loop, długi ciąg, z: 4.38 usec per loopi bez: 7.03 usec per loop. (Uwaga: nie są one bezpośrednio porównywalne z powyższymi wynikami, ponieważ jest to inna maszyna itp.)
Hugo,
1
@Hugo; Myślę, że ta różnica w czasie wynika z tego, że replacewywoływana jest tylko wtedy, gdy cwystępuje textw przypadku, bagdy jest wywoływana w każdej iteracji w ab.
haccks
2
@haccks Dzięki, zaktualizowałem swoją odpowiedź o dalsze terminy: dodanie sprawdzania jest lepsze dla obu, ale największą lekcją jest to, że Python 3 jest nawet 3 razy szybszy!
Hugo,
73
>>> string="abc&def#ghi">>>for ch in['&','#']:...if ch in string:... string=string.replace(ch,"\\"+ch)...>>>print string
abc\&def\#ghi
Dlaczego potrzebny był podwójny ukośnik odwrotny? Dlaczego po prostu „\” nie działa?
axolotl
3
Podwójny odwrotny ukośnik unika odwrotnego ukośnika, w przeciwnym razie Python interpretowałby „\” jako dosłowny znak cudzysłowu w wciąż otwartym ciągu.
Riet
Dlaczego trzeba string=string.replace(ch,"\\"+ch)? Czy to nie string.replace(ch,"\\"+ch)wystarczy?
MattSom,
1
@MattSom replace () nie modyfikuje oryginalnego ciągu, ale zwraca kopię. Potrzebujesz więc przypisania, aby kod zadziałał.
Ben Brian,
3
Czy naprawdę potrzebujesz tego? Wygląda to na powielanie tego, co i tak zastąpi.
Późno na imprezę, ale straciłem dużo czasu z tym problemem, dopóki nie znalazłem odpowiedzi.
Krótki i słodki, translatejest lepszy odreplace . Jeśli bardziej interesuje Cię funkcjonalność w czasie, nie używaj replace.
Użyj również, translatejeśli nie wiesz, czy zestaw znaków do zastąpienia nakłada się na zestaw znaków używanych do zamiany.
Przykładem:
Korzystając z replaceCiebie, naiwnie oczekujesz, że fragment kodu "1234".replace("1", "2").replace("2", "3").replace("3", "4")wróci "2344", ale w rzeczywistości wróci "4444".
Tłumaczenie wydaje się wykonywać to, czego pierwotnie chciał OP.
Możesz rozważyć napisanie ogólnej funkcji zmiany znaczenia:
def mk_esc(esc_chars):returnlambda s:''.join(['\\'+ c if c in esc_chars else c for c in s])>>> esc = mk_esc('&#')>>>print esc('Learn & be #1')Learn \& be \#1
W ten sposób możesz skonfigurować swoją funkcję za pomocą listy znaków, które należy uciec.
Do twojej wiadomości, jest to mało przydatne lub nieprzydatne dla OP, ale może być przydatne dla innych czytelników (proszę nie głosować, jestem tego świadomy).
Jako nieco niedorzeczne, ale interesujące ćwiczenie, chciałem sprawdzić, czy mogę użyć programowania funkcjonalnego Pythona do zastąpienia wielu znaków. Jestem prawie pewien, że to nie bije tylko wywołania metody replace () dwa razy. A jeśli wydajność była problemem, możesz łatwo pokonać to w rdzeniu, C, Julii, Perlu, Javie, javascript, a może nawet awk. Korzysta z zewnętrznego pakietu „pomocników” o nazwie pytoolz , przyspieszanego przez cython ( cytoolz, jest to pakiet pypi ).
from cytoolz.functoolz import compose
from cytoolz.itertoolz import chain,sliding_window
from itertools import starmap,imap,ifilter
from operator import itemgetter,contains
text='&hello#hi&yo&'
char_index_iter=compose(partial(imap, itemgetter(0)), partial(ifilter, compose(partial(contains,'#&'), itemgetter(1))), enumerate)print'\\'.join(imap(text.__getitem__, starmap(slice, sliding_window(2, chain((0,), char_index_iter(text),(len(text),))))))
Nie zamierzam nawet tego wyjaśniać, ponieważ nikt nie zawracałby sobie głowy użyciem tego do wielokrotnego zastąpienia. Mimo to czułem, że jestem w tym pewien, że mogłem zainspirować innych czytelników lub wygrać konkurs zaciemniania kodu.
Używając funkcji zmniejsz, która jest dostępna w python2.7 i python3. *, Możesz łatwo zastąpić wiele podciągów w czysty i pythoniczny sposób.
# Lets define a helper method to make it easy to usedef replacer(text, replacements):return reduce(lambda text, ptuple: text.replace(ptuple[0], ptuple[1]),
replacements, text
)if __name__ =='__main__':
uncleaned_str ="abc&def#ghi"
cleaned_str = replacer(uncleaned_str,[("&","\&"),("#","\#")])print(cleaned_str)# "abc\&def\#ghi"
W python2.7 nie musisz importować redukcji, ale w python3. * Musisz zaimportować go z modułu funkools.
>>> a ='&#'>>>print a.replace('&', r'\&')
\&#>>>print a.replace('#', r'\#')&\#
>>>
Chcesz użyć „nieprzetworzonego” ciągu (oznaczonego przedrostkiem „r” przed zastępującym ciągiem), ponieważ nieprzetworzone ciągi nie będą specjalnie traktować odwrotnego ukośnika.
Odpowiedzi:
Zastąpienie dwóch znaków
Zmierzyłem wszystkie metody w bieżących odpowiedziach wraz z jedną dodatkową.
Z ciągiem wejściowym
abc&def#ghi
i zastąpienie & -> \ & i # -> \ #, najszybszym sposobem było łańcucha razem zamienniki tak:text.replace('&', '\&').replace('#', '\#')
.Czasy dla każdej funkcji:
Oto funkcje:
Czasowo tak:
Zamiana 17 znaków
Oto podobny kod, aby zrobić to samo, ale z większą ilością znaków do ucieczki (\ `* _ {}> # + -.! $):
Oto wyniki dla tego samego ciągu wejściowego
abc&def#ghi
:I przy dłuższym ciągu wejściowym (
## *Something* and [another] thing in a longer sentence with {more} things to replace$
):Dodanie kilku wariantów:
Przy krótszym wejściu:
Przy dłuższym wejściu:
Więc
ba
użyję dla czytelności i szybkości.Uzupełnienie
Podpowiedzi hacck w komentarzach, jedna różnica między
ab
iba
jestif c in text:
czek. Przetestujmy je pod kątem jeszcze dwóch wariantów:Czasy w μs na pętlę w Pythonie 2.7.14 i 3.6.3 i na innym komputerze niż wcześniejszy zestaw, więc nie można bezpośrednio porównać.
Możemy stwierdzić, że:
Osoby z czekiem są nawet 4x szybsze niż osoby bez czeku
ab_with_check
jest nieco na czele w Pythonie 3, aleba
(z czekiem) ma większą przewagę w Pythonie 2Jednak największą lekcją tutaj jest to, że Python 3 jest do 3 razy szybszy niż Python 2 ! Nie ma ogromnej różnicy między najwolniejszym w Pythonie 3 i najszybszym w Pythonie 2!
źródło
if c in text:
konieczne jest wba
?1.45 usec per loop
i bez:5.3 usec per loop
, długi ciąg, z:4.38 usec per loop
i bez:7.03 usec per loop
. (Uwaga: nie są one bezpośrednio porównywalne z powyższymi wynikami, ponieważ jest to inna maszyna itp.)replace
wywoływana jest tylko wtedy, gdyc
występujetext
w przypadku,ba
gdy jest wywoływana w każdej iteracji wab
.źródło
string=string.replace(ch,"\\"+ch)
? Czy to niestring.replace(ch,"\\"+ch)
wystarczy?Po prostu połącz takie
replace
funkcjeJeśli zamienników będzie więcej, możesz to zrobić w ten ogólny sposób
źródło
Oto metoda python3 wykorzystująca
str.translate
istr.maketrans
:Wydrukowany ciąg to
abc\&def\#ghi
.źródło
.translate()
wydaje się być wolniejsze niż trzy powiązane.replace()
(używając CPython 3.6.4).replace()
siebie, ale dodałem tę odpowiedź ze względu na kompletność.'\#'
ważne Nie powinno to byćr'\#'
albo'\\#'
? Może to być problem z formatowaniem bloku kodu.Czy zawsze zamierzasz wstawić ukośnik odwrotny? Jeśli tak, spróbuj
Może nie jest to najskuteczniejsza metoda, ale myślę, że jest najłatwiejsza.
źródło
r'\\\1'
Późno na imprezę, ale straciłem dużo czasu z tym problemem, dopóki nie znalazłem odpowiedzi.
Krótki i słodki,
translate
jest lepszy odreplace
. Jeśli bardziej interesuje Cię funkcjonalność w czasie, nie używajreplace
.Użyj również,
translate
jeśli nie wiesz, czy zestaw znaków do zastąpienia nakłada się na zestaw znaków używanych do zamiany.Przykładem:
Korzystając z
replace
Ciebie, naiwnie oczekujesz, że fragment kodu"1234".replace("1", "2").replace("2", "3").replace("3", "4")
wróci"2344"
, ale w rzeczywistości wróci"4444"
.Tłumaczenie wydaje się wykonywać to, czego pierwotnie chciał OP.
źródło
Możesz rozważyć napisanie ogólnej funkcji zmiany znaczenia:
W ten sposób możesz skonfigurować swoją funkcję za pomocą listy znaków, które należy uciec.
źródło
Do twojej wiadomości, jest to mało przydatne lub nieprzydatne dla OP, ale może być przydatne dla innych czytelników (proszę nie głosować, jestem tego świadomy).
Jako nieco niedorzeczne, ale interesujące ćwiczenie, chciałem sprawdzić, czy mogę użyć programowania funkcjonalnego Pythona do zastąpienia wielu znaków. Jestem prawie pewien, że to nie bije tylko wywołania metody replace () dwa razy. A jeśli wydajność była problemem, możesz łatwo pokonać to w rdzeniu, C, Julii, Perlu, Javie, javascript, a może nawet awk. Korzysta z zewnętrznego pakietu „pomocników” o nazwie pytoolz , przyspieszanego przez cython ( cytoolz, jest to pakiet pypi ).
Nie zamierzam nawet tego wyjaśniać, ponieważ nikt nie zawracałby sobie głowy użyciem tego do wielokrotnego zastąpienia. Mimo to czułem, że jestem w tym pewien, że mogłem zainspirować innych czytelników lub wygrać konkurs zaciemniania kodu.
źródło
Używając funkcji zmniejsz, która jest dostępna w python2.7 i python3. *, Możesz łatwo zastąpić wiele podciągów w czysty i pythoniczny sposób.
W python2.7 nie musisz importować redukcji, ale w python3. * Musisz zaimportować go z modułu funkools.
źródło
Może prosta pętla do zastąpienia znaków:
źródło
Co powiesz na to?
następnie
wynik
podobny do odpowiedzi
źródło
Chcesz użyć „nieprzetworzonego” ciągu (oznaczonego przedrostkiem „r” przed zastępującym ciągiem), ponieważ nieprzetworzone ciągi nie będą specjalnie traktować odwrotnego ukośnika.
źródło
zaawansowany sposób za pomocą wyrażenia regularnego
źródło