Muszę zastąpić niektóre znaki w następujący sposób: &
➔ \&
, #
➔ \#
, ...
Kodowałem w następujący sposób, ale myślę, że powinien istnieć lepszy sposób. Jakieś wskazówki?
strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...
Muszę zastąpić niektóre znaki w następujący sposób: &
➔ \&
, #
➔ \#
, ...
Kodowałem w następujący sposób, ale myślę, że powinien istnieć lepszy sposób. Jakieś wskazówki?
strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...
Odpowiedzi:
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:
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):
return lambda 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'\#')
Czasowo tak:
python -mtimeit -s"import time_functions" "time_functions.a('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.b('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.c('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.d('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.e('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.f('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.g('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.h('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.i('abc&def#ghi')"
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):
return lambda 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
:
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:
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:
Przy dłuższym wejściu:
Więc ba
użyję dla czytelności i szybkości.
Podpowiedzi hacck w komentarzach, jedna różnica między ab
i ba
jest 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_check
jest 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!
if c in text:
konieczne jest w ba
?
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, gdy c
występuje text
w przypadku, ba
gdy jest wywoływana w każdej iteracji w ab
.
>>> string="abc&def#ghi"
>>> for ch in ['&','#']:
... if ch in string:
... string=string.replace(ch,"\\"+ch)
...
>>> print string
abc\&def\#ghi
string=string.replace(ch,"\\"+ch)
? Czy to nie string.replace(ch,"\\"+ch)
wystarczy?
Po prostu połącz takie replace
funkcje
strs = "abc&def#ghi"
print strs.replace('&', '\&').replace('#', '\#')
# abc\&def\#ghi
Jeśli zamienników będzie więcej, możesz to zrobić w ten ogólny sposób
strs, replacements = "abc&def#ghi", {"&": "\&", "#": "\#"}
print "".join([replacements.get(c, c) for c in strs])
# abc\&def\#ghi
Oto metoda python3 wykorzystująca str.translate
i str.maketrans
:
s = "abc&def#ghi"
print(s.translate(str.maketrans({'&': '\&', '#': '\#'})))
Wydrukowany ciąg to abc\&def\#ghi
.
.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
import re
rx = re.compile('([&#])')
# ^^ fill in the characters here.
strs = rx.sub('\\\\\\1', strs)
Może nie jest to najskuteczniejsza metoda, ale myślę, że jest najłatwiejsza.
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żywaj replace
.
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.
Możesz rozważyć napisanie ogólnej funkcji zmiany znaczenia:
def mk_esc(esc_chars):
return lambda 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 use
def 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.
Może prosta pętla do zastąpienia znaków:
a = '&#'
to_replace = ['&', '#']
for char in to_replace:
a = a.replace(char, "\\"+char)
print(a)
>>> \&\#
Co powiesz na to?
def replace_all(dict, str):
for key in dict:
str = str.replace(key, dict[key])
return str
następnie
print(replace_all({"&":"\&", "#":"\#"}, "&#"))
wynik
\&\#
podobny do odpowiedzi