web-dev-qa-db-de.com

Ersetzen Sie mehrere Zeichen durch Python

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('#', '\#')
...
141
prosseek

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 dem Ersetzen von & ->\& und # -> # war es am schnellsten, 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):
    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')"

17 Zeichen ersetzen

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:

  • 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

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:

  • 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

Aus Gründen der Lesbarkeit und Geschwindigkeit verwende ich ba.

Nachtrag

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!

326
Hugo
>>> string="abc&def#ghi"
>>> for ch in ['&','#']:
...   if ch in string:
...      string=string.replace(ch,"\\"+ch)
...
>>> print string
abc\&def\#ghi
71
ghostdog74

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
27
thefourtheye

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.

15

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.

14
kennytm

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.

6
Victor Olex

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.

4
Sebastialonso

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.

3
parity3

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.

1
CasualCoder3
>>> 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.

0
jonesy