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 habe alle Methoden in den aktuellen Antworten zusammen mit einer zusätzlichen zeitlich festgelegt.
Mit einer Eingabezeichenfolge von abc&def#ghi
Und dem Ersetzen von & ->\& und # -> # war es am schnellsten, 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 so:
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, jedoch mit mehr zu entziehenden 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$
):
Ein paar Varianten hinzufügen:
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:
Aus Gründen der Lesbarkeit und Geschwindigkeit verwende ich ba
.
Ein Unterschied zwischen ab
und ba
ist der if c in text:
- Check. 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 auf Python 2.7.14 und 3.6.3 und auf einer anderen Maschine als der zuvor festgelegten, 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 Scheck
ab_with_check
Liegt bei Python 3 leicht in Führung, aber ba
(mit Häkchen) hat bei Python 2 einen größeren Vorsprung
Die größte Lektion hier ist jedoch Python 3 ist bis zu 3x schneller als Python 2! Es gibt keinen großen Unterschied zwischen dem langsamsten auf Python 3 und dem schnellsten auf Python 2!
>>> string="abc&def#ghi"
>>> for ch in ['&','#']:
... if ch in string:
... string=string.replace(ch,"\\"+ch)
...
>>> print string
abc\&def\#ghi
Verketten Sie einfach die replace
-Funktionen wie folgt
strs = "abc&def#ghi"
print strs.replace('&', '\&').replace('#', '\#')
# abc\&def\#ghi
Wenn die Anzahl der Ersetzungen zunimmt, 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
.
Wirst du immer einen Backslash voranstellen? Wenn ja, versuche 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.
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, die maskiert werden sollen, konfigurierbar machen.
Spät zur Party, aber ich habe viel Zeit mit diesem Thema verloren, bis ich meine Antwort gefunden habe.
Kurz und gut, translate
ist replace
überlegen. Wenn Sie sich mehr für die Optimierung der Funktionalität über einen längeren Zeitraum interessieren, verwenden Sie replace
nicht.
Verwenden Sie auch translate
, wenn Sie nicht wissen, ob der zu ersetzende Zeichensatz den zu ersetzenden Zeichensatz überlappt.
Ein typisches Beispiel:
Wenn Sie replace
verwenden, würden Sie naiv erwarten, dass das Snippet "1234".replace("1", "2").replace("2", "3").replace("3", "4")
"2344"
Zurückgibt, aber tatsächlich "4444"
.
Die Übersetzung scheint das zu leisten, was das OP ursprünglich wollte.
Zu Ihrer Information, dies ist für das OP von geringem oder gar keinem Nutzen, kann jedoch für andere Leser von Nutzen sein (bitte stimmen Sie nicht ab, ich bin mir dessen bewusst).
Als eine etwas lächerliche, aber interessante Übung wollte ich sehen, ob ich python funktionale Programmierung verwenden könnte, um mehrere Zeichen zu ersetzen. Ich bin mir ziemlich sicher, dass dies NICHT besser ist, als nur zweimal replace () aufzurufen. Und wenn Leistung war ein Problem, das Sie in Rust, C, Julia, Perl, Java, Javascript und vielleicht sogar awk leicht übertreffen können. 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, weil sich niemand die Mühe machen würde, dies zu verwenden, um ein mehrfaches Ersetzen zu erreichen. Trotzdem fühlte ich mich in dieser Hinsicht etwas versiert und dachte, es könnte andere Leser inspirieren oder einen Code-Verschleierungswettbewerb gewinnen.
Mit dem in python2.7 und python3. * Verfügbaren Befehl "Reduzieren" können Sie mehrere Teilzeichenfolgen auf einfache 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 __== '__main__':
uncleaned_str = "abc&def#ghi"
cleaned_str = replacer(uncleaned_str, [("&","\&"),("#","\#")])
print(cleaned_str) # "abc\&def\#ghi"
In python2.7 müssen Sie nicht reduct importieren, sondern in python3. * Müssen Sie es aus dem functools-Modul importieren.
>>> a = '&#'
>>> print a.replace('&', r'\&')
\&#
>>> print a.replace('#', r'\#')
&\#
>>>
Sie möchten eine 'rohe' Zeichenfolge (gekennzeichnet durch das 'r' vor der Ersetzungszeichenfolge) verwenden, da rohe Zeichenfolgen den umgekehrten Schrägstrich nicht speziell behandeln.