Ich muss einige Zeichen wie folgt ersetzen: &
➔ \&
, #
➔ \#
, ...
Ich habe wie folgt codiert, aber ich denke, es sollte einen besseren Weg geben. Irgendwelche Hinweise?
strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...
Ich muss einige Zeichen wie folgt ersetzen: &
➔ \&
, #
➔ \#
, ...
Ich habe wie folgt codiert, aber ich denke, es sollte einen besseren Weg geben. Irgendwelche Hinweise?
strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...
Antworten:
Ich habe alle Methoden in den aktuellen Antworten zusammen mit einer zusätzlichen zeitlich festgelegt.
Mit einer Eingabezeichenfolge von abc&def#ghi
und Ersetzen von & -> \ & und # -> \ # war der schnellste Weg, die Ersetzungen wie folgt zu verketten : text.replace('&', '\&').replace('#', '\#')
.
Timings für jede Funktion:
Hier sind die Funktionen:
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'\#')
Zeitlich wie folgt:
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')"
Hier ist ein ähnlicher Code, um dasselbe zu tun, aber mit mehr zu entkommenden Zeichen (\ `* _ {}> # + -.! $):
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'\$')
Hier sind die Ergebnisse für dieselbe Eingabezeichenfolge abc&def#ghi
:
Und mit einer längeren Eingabezeichenfolge ( ## *Something* and [another] thing in a longer sentence with {more} things to replace$
):
Hinzufügen einiger Varianten:
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)
Mit der kürzeren Eingabe:
Mit der längeren Eingabe:
Also werde ich ba
für Lesbarkeit und Geschwindigkeit verwenden.
Aufgefordert durch Haccks in den Kommentaren ist ein Unterschied zwischen ab
und ba
die if c in text:
Prüfung. Testen wir sie gegen zwei weitere Varianten:
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)
Zeiten in μs pro Schleife unter Python 2.7.14 und 3.6.3 sowie auf einem anderen Computer als dem vorherigen Satz können daher nicht direkt verglichen werden.
╭────────────╥──────┬───────────────┬──────┬──────────────────╮
│ 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 │
└────────────╨──────┴───────────────┴──────┴──────────────────┘
Können wir schließen, dass:
Diejenigen mit dem Scheck sind bis zu 4x schneller als diejenigen ohne den Scheck
ab_with_check
liegt bei Python 3 leicht an der Spitze, hat aber ba
(mit Häkchen) bei Python 2 einen größeren Vorsprung
Die größte Lektion hier ist jedoch, dass Python 3 bis zu dreimal schneller ist als Python 2 ! Es gibt keinen großen Unterschied zwischen dem langsamsten in Python 3 und dem schnellsten in Python 2!
if c in text:
notwendig ba
?
1.45 usec per loop
und ohne : 5.3 usec per loop
, Lange Saite, mit: 4.38 usec per loop
und ohne : 7.03 usec per loop
. (Beachten Sie, dass diese nicht direkt mit den obigen Ergebnissen vergleichbar sind, da es sich um eine andere Maschine usw. handelt.)
replace
nur aufgerufen wird, wenn er c
gefunden text
wird, ba
während er in jeder Iteration in aufgerufen wird 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)
? Ist das nicht string.replace(ch,"\\"+ch)
genug?
Verketten Sie einfach die replace
Funktionen wie folgt
strs = "abc&def#ghi"
print strs.replace('&', '\&').replace('#', '\#')
# abc\&def\#ghi
Wenn die Anzahl der Ersetzungen größer sein soll, können Sie dies auf diese generische Weise tun
strs, replacements = "abc&def#ghi", {"&": "\&", "#": "\#"}
print "".join([replacements.get(c, c) for c in strs])
# abc\&def\#ghi
Hier ist eine Python3-Methode mit str.translate
und str.maketrans
:
s = "abc&def#ghi"
print(s.translate(str.maketrans({'&': '\&', '#': '\#'})))
Die gedruckte Zeichenfolge ist abc\&def\#ghi
.
.translate()
scheint eine langsamer zu sein als drei verkettete .replace()
(mit CPython 3.6.4).
replace()
ich mich selbst verwenden, aber ich habe diese Antwort der Vollständigkeit halber hinzugefügt.
'\#'
gültig? sollte es nicht sein r'\#'
oder '\\#'
? Könnte möglicherweise ein Problem bei der Formatierung von Codeblöcken sein.
Wirst du immer einen Backslash voranstellen? Wenn ja, versuchen Sie es
import re
rx = re.compile('([&#])')
# ^^ fill in the characters here.
strs = rx.sub('\\\\\\1', strs)
Es ist vielleicht nicht die effizienteste Methode, aber ich denke, es ist die einfachste.
r'\\\1'
Spät zur Party, aber ich habe viel Zeit mit diesem Thema verloren, bis ich meine Antwort gefunden habe.
Kurz und bündig, translate
ist überlegenreplace
. Wenn Sie mehr an der Optimierung der Funktionalität im Laufe der Zeit interessiert sind, verwenden Sie diese nicht replace
.
Verwenden translate
Sie diese Option auch, wenn Sie nicht wissen, ob der zu ersetzende Zeichensatz den zum Ersetzen verwendeten Zeichensatz überlappt.
Ein typisches Beispiel:
Wenn replace
Sie verwenden, würden Sie naiv erwarten, dass das Snippet "1234".replace("1", "2").replace("2", "3").replace("3", "4")
zurückkehrt "2344"
, aber es wird tatsächlich zurückkehren "4444"
.
Die Übersetzung scheint das zu leisten, was OP ursprünglich gewünscht hatte.
Sie können eine generische Escape-Funktion schreiben:
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
Auf diese Weise können Sie Ihre Funktion mit einer Liste von Zeichen konfigurieren, die maskiert werden sollen.
Zu Ihrer Information, dies ist für das OP von geringem oder keinem Nutzen, kann aber für andere Leser von Nutzen sein (bitte stimmen Sie nicht ab, ich bin mir dessen bewusst).
Als etwas lächerliche, aber interessante Übung wollte ich sehen, ob ich Python-Funktionsprogrammierung verwenden kann, um mehrere Zeichen zu ersetzen. Ich bin mir ziemlich sicher, dass dies NICHT besser ist, als zweimal replace () aufzurufen. Und wenn Leistung ein Problem wäre, könnten Sie dies leicht in Rost, C, Julia, Perl, Java, Javascript und vielleicht sogar awk schlagen. Es verwendet ein externes ' Helfer' -Paket namens Pytoolz , das über Cython beschleunigt wird ( Cytoolz, es ist ein Pypi-Paket ).
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),))))))
Ich werde dies nicht einmal erklären, da sich niemand die Mühe machen würde, dies zu verwenden, um mehrere Ersetzungen durchzuführen. Trotzdem fühlte ich mich dabei etwas erfolgreich und dachte, es könnte andere Leser inspirieren oder einen Code-Verschleierungswettbewerb gewinnen.
Mit reduct, das in Python2.7 und Python3 verfügbar ist. * Sie können problemlos mehrere Teilzeichenfolgen auf saubere und pythonische Weise ersetzen.
# 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"
In Python2.7 müssen Sie Reduce nicht importieren, aber in Python3. * Müssen Sie es aus dem functools-Modul importieren.
Vielleicht eine einfache Schleife, die Zeichen ersetzen sollen:
a = '&#'
to_replace = ['&', '#']
for char in to_replace:
a = a.replace(char, "\\"+char)
print(a)
>>> \&\#
Wie wäre es damit?
def replace_all(dict, str):
for key in dict:
str = str.replace(key, dict[key])
return str
dann
print(replace_all({"&":"\&", "#":"\#"}, "&#"))
Ausgabe
\&\#
ähnlich zu beantworten