Ich habe alle Methoden in den aktuellen Antworten zusammen mit einer zusätzlichen zeitlich festgelegt.
Mit einer Eingabezeichenfolge von abc&def#ghiund Ersetzen von & -> \ & und # -> \ # war der schnellste Weg, die Ersetzungen wie folgt zu verketten : text.replace('&', '\&').replace('#', '\#').
Timings für jede Funktion:
a) 1000000 Schleifen, am besten 3: 1,47 μs pro Schleife
b) 1000000 Schleifen, am besten 3: 1,51 μs pro Schleife
c) 100000 Schleifen, am besten 3: 12,3 μs pro Schleife
d) 100000 Schleifen, am besten 3: 12 μs pro Schleife
e) 100000 Schleifen, am besten 3: 3,27 μs pro Schleife
f) 1000000 Schleifen, am besten 3: 0,817 μs pro Schleife
g) 100000 Schleifen, am besten 3: 3,64 μs pro Schleife
h) 1000000 Schleifen, am besten 3: 0,927 μs pro Schleife
i) 1000000 Schleifen, am besten 3: 0,814 μs pro Schleife
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):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'\#')
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):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'\$')
Hier sind die Ergebnisse für dieselbe Eingabezeichenfolge abc&def#ghi:
a) 100000 Schleifen, am besten 3: 6,72 μs pro Schleife
b) 100000 Schleifen, am besten 3: 2,64 μs pro Schleife
c) 100000 Schleifen, am besten 3: 11,9 μs pro Schleife
d) 100000 Schleifen, am besten 3: 4,92 μs pro Schleife
e) 100000 Schleifen, am besten 3: 2,96 μs pro Schleife
f) 100000 Schleifen, am besten 3: 4,29 μs pro Schleife
g) 100000 Schleifen, am besten 3: 4,68 μs pro Schleife
h) 100000 Schleifen, am besten 3: 4,73 μs pro Schleife
i) 100000 Schleifen, am besten 3: 4,24 μs pro Schleife
Und mit einer längeren Eingabezeichenfolge ( ## *Something* and [another] thing in a longer sentence with {more} things to replace$):
a) 100000 Schleifen, am besten 3: 7,59 μs pro Schleife
b) 100000 Schleifen, am besten 3: 6,54 μs pro Schleife
c) 100000 Schleifen, am besten 3: 16,9 μs pro Schleife
d) 100000 Schleifen, am besten 3: 7,29 μs pro Schleife
e) 100000 Schleifen, am besten 3: 12,2 μs pro Schleife
f) 100000 Schleifen, am besten 3: 5,38 μs pro Schleife
g) 10000 Schleifen, am besten 3: 21,7 μs pro Schleife
h) 100000 Schleifen, am besten 3: 5,7 μs pro Schleife
i) 100000 Schleifen, am besten 3: 5,13 μs pro Schleife
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:
ab) 100000 Schleifen, am besten 3: 7,05 μs pro Schleife
ba) 100000 Schleifen, am besten 3: 2,4 μs pro Schleife
Mit der längeren Eingabe:
ab) 100000 Schleifen, am besten 3: 7,71 μs pro Schleife
ba) 100000 Schleifen, am besten 3: 6,08 μs pro Schleife
Also werde ich bafür Lesbarkeit und Geschwindigkeit verwenden.
Nachtrag
Aufgefordert durch Haccks in den Kommentaren ist ein Unterschied zwischen abund badie 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_checkliegt 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!
@haccks Es ist nicht notwendig, aber es ist 2-3x schneller damit. Kurze Saite, mit: 1.45 usec per loopund ohne : 5.3 usec per loop, Lange Saite, mit: 4.38 usec per loopund 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.)
Hugo
1
@Hugo; Ich denke, dieser Zeitunterschied ist darauf zurückzuführen, dass replacenur aufgerufen wird, wenn er cgefunden textwird, bawährend er in jeder Iteration in aufgerufen wird ab.
Haccks
2
@haccks Danke, ich habe meine Antwort mit weiteren Timings aktualisiert: Das Hinzufügen des Checks ist für beide besser, aber die größte Lektion ist, dass Python 3 bis zu 3x schneller ist!
Hugo
73
>>> string="abc&def#ghi">>>for ch in['&','#']:...if ch in string:... string=string.replace(ch,"\\"+ch)...>>>print string
abc\&def\#ghi
Warum wurde ein doppelter Backslash benötigt? Warum funktioniert nicht einfach "\"?
Axolotl
3
Der doppelte Backslash entgeht dem Backslash, andernfalls würde Python "\" als wörtliches Anführungszeichen in einer noch offenen Zeichenfolge interpretieren.
Riet
Warum musst du string=string.replace(ch,"\\"+ch)? Ist das nicht string.replace(ch,"\\"+ch)genug?
MattSom
1
@MattSom replace () ändert die ursprüngliche Zeichenfolge nicht, gibt jedoch eine Kopie zurück. Sie benötigen also die Zuweisung, damit der Code eine Wirkung hat.
Ben Brian
3
Benötigen Sie wirklich das Wenn? Es sieht aus wie eine Verdoppelung dessen, was der Ersatz sowieso tun wird.
Lorenzo
32
Verketten Sie einfach die replaceFunktionen wie folgt
Dies ist eine gute Antwort, aber in der Praxis .translate()scheint eine langsamer zu sein als drei verkettete .replace()(mit CPython 3.6.4).
Changaco
@Changaco Vielen Dank für das Timing 👍 In der Praxis würde replace()ich mich selbst verwenden, aber ich habe diese Antwort der Vollständigkeit halber hinzugefügt.
Tommy.carstensen
Für große Saiten und viele Ersetzungen sollte dies schneller sein, obwohl einige Tests schön wären ...
Graipher
Nun, es ist nicht auf meiner Maschine (das gleiche gilt für 2 und 17 Ersatz).
Graipher
Wie ist '\#'gültig? sollte es nicht sein r'\#'oder '\\#'? Könnte möglicherweise ein Problem bei der Formatierung von Codeblöcken sein.
Parität3
16
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.
Spät zur Party, aber ich habe viel Zeit mit diesem Thema verloren, bis ich meine Antwort gefunden habe.
Kurz und bündig, translateist überlegenreplace . Wenn Sie mehr an der Optimierung der Funktionalität im Laufe der Zeit interessiert sind, verwenden Sie diese nicht replace.
Verwenden translateSie diese Option auch, wenn Sie nicht wissen, ob der zu ersetzende Zeichensatz den zum Ersetzen verwendeten Zeichensatz überlappt.
Ein typisches Beispiel:
Wenn replaceSie 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):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
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 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"
In Python2.7 müssen Sie Reduce nicht importieren, aber 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 verwenden (gekennzeichnet durch das 'r', das der Ersatzzeichenfolge vorangestellt ist), da rohe Zeichenfolgen den Backslash nicht speziell behandeln sollen.
Antworten:
Zwei Zeichen ersetzen
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:
Zeitlich wie folgt:
17 Zeichen ersetzen
Hier ist ein ähnlicher Code, um dasselbe zu tun, aber mit mehr zu entkommenden Zeichen (\ `* _ {}> # + -.! $):
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:
Mit der kürzeren Eingabe:
Mit der längeren Eingabe:
Also werde ich
ba
für Lesbarkeit und Geschwindigkeit verwenden.Nachtrag
Aufgefordert durch Haccks in den Kommentaren ist ein Unterschied zwischen
ab
undba
dieif c in text:
Prüfung. Testen wir sie gegen zwei weitere Varianten: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.
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 aberba
(mit Häkchen) bei Python 2 einen größeren VorsprungDie 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!
quelle
if c in text:
notwendigba
?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 erc
gefundentext
wird,ba
während er in jeder Iteration in aufgerufen wirdab
.quelle
string=string.replace(ch,"\\"+ch)
? Ist das nichtstring.replace(ch,"\\"+ch)
genug?Verketten Sie einfach die
replace
Funktionen wie folgtWenn die Anzahl der Ersetzungen größer sein soll, können Sie dies auf diese generische Weise tun
quelle
Hier ist eine Python3-Methode mit
str.translate
undstr.maketrans
:Die gedruckte Zeichenfolge ist
abc\&def\#ghi
.quelle
.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 seinr'\#'
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
Es ist vielleicht nicht die effizienteste Methode, aber ich denke, es ist die einfachste.
quelle
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 nichtreplace
.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.
quelle
Sie können eine generische Escape-Funktion schreiben:
Auf diese Weise können Sie Ihre Funktion mit einer Liste von Zeichen konfigurieren, die maskiert werden sollen.
quelle
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 ).
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.
quelle
Mit reduct, das in Python2.7 und Python3 verfügbar ist. * Sie können problemlos mehrere Teilzeichenfolgen auf saubere und pythonische Weise ersetzen.
In Python2.7 müssen Sie Reduce nicht importieren, aber in Python3. * Müssen Sie es aus dem functools-Modul importieren.
quelle
Vielleicht eine einfache Schleife, die Zeichen ersetzen sollen:
quelle
Wie wäre es damit?
dann
Ausgabe
ähnlich zu beantworten
quelle
Sie möchten eine 'rohe' Zeichenfolge verwenden (gekennzeichnet durch das 'r', das der Ersatzzeichenfolge vorangestellt ist), da rohe Zeichenfolgen den Backslash nicht speziell behandeln sollen.
quelle