Devo sostituire alcuni caratteri come segue: &
➔ \&
, #
➔ \#
, ...
Ho codificato come segue, ma suppongo ci dovrebbe essere un modo migliore. Qualche suggerimento?
strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...
Devo sostituire alcuni caratteri come segue: &
➔ \&
, #
➔ \#
, ...
Ho codificato come segue, ma suppongo ci dovrebbe essere un modo migliore. Qualche suggerimento?
strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...
Risposte:
Ho cronometrato tutti i metodi nelle risposte correnti insieme a uno in più.
Con una stringa di input di abc&def#ghi
e sostituzione e -> \ & e # -> \ #, il modo più veloce è stato quello di concatenare le sostituzioni come questo: text.replace('&', '\&').replace('#', '\#')
.
Tempi per ciascuna funzione:
Ecco le funzioni:
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'\#')
Cronometrato in questo modo:
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')"
Ecco un codice simile per fare lo stesso, ma con più caratteri per fuggire (\ `* _ {}> # + -.! $):
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'\$')
Ecco i risultati per la stessa stringa di input abc&def#ghi
:
E con una stringa di input più lunga ( ## *Something* and [another] thing in a longer sentence with {more} things to replace$
):
Aggiunta di un paio di varianti:
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)
Con l'input più breve:
Con l'input più lungo:
Quindi userò ba
per leggibilità e velocità.
Spinto da hacck nei commenti, una differenza tra ab
e ba
è il if c in text:
controllo. Proviamoli con altre due varianti:
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)
Tempi in μs per loop su Python 2.7.14 e 3.6.3 e su una macchina diversa dal set precedente, quindi non possono essere confrontati direttamente.
╭────────────╥──────┬───────────────┬──────┬──────────────────╮
│ 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 │
└────────────╨──────┴───────────────┴──────┴──────────────────┘
Possiamo concludere che:
Quelli con il controllo sono fino a 4 volte più veloci di quelli senza controllo
ab_with_check
è leggermente in vantaggio su Python 3, ma ba
(con segno di spunta) ha un vantaggio maggiore su Python 2
Tuttavia, la lezione più grande qui è che Python 3 è fino a 3 volte più veloce di Python 2 ! Non c'è un'enorme differenza tra il più lento su Python 3 e il più veloce su Python 2!
if c in text:
necessario in ba
?
1.45 usec per loop
e senza: 5.3 usec per loop
, stringa lungo, con: 4.38 usec per loop
e senza: 7.03 usec per loop
. (Nota che questi non sono direttamente confrontabili con i risultati sopra, perché è una macchina diversa, ecc.)
replace
viene chiamata solo quando c
viene trovata text
nel caso in cui ba
viene chiamata in ogni iterazione in 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)
? Non è string.replace(ch,"\\"+ch)
abbastanza?
Incatenate semplicemente le replace
funzioni in questo modo
strs = "abc&def#ghi"
print strs.replace('&', '\&').replace('#', '\#')
# abc\&def\#ghi
Se le sostituzioni saranno più numerose, puoi farlo in questo modo generico
strs, replacements = "abc&def#ghi", {"&": "\&", "#": "\#"}
print "".join([replacements.get(c, c) for c in strs])
# abc\&def\#ghi
Ecco un metodo python3 usando str.translate
e str.maketrans
:
s = "abc&def#ghi"
print(s.translate(str.maketrans({'&': '\&', '#': '\#'})))
La stringa stampata è abc\&def\#ghi
.
.translate()
sembra essere più lento di tre concatenati .replace()
(usando CPython 3.6.4).
replace()
, ma ho aggiunto questa risposta per completezza.
'\#'
valido? non dovrebbe essere r'\#'
o '\\#'
? Potrebbe essere forse un problema di formattazione del blocco di codice.
Hai sempre intenzione di anteporre una barra rovesciata? Se è così, prova
import re
rx = re.compile('([&#])')
# ^^ fill in the characters here.
strs = rx.sub('\\\\\\1', strs)
Potrebbe non essere il metodo più efficiente ma penso che sia il più semplice.
r'\\\1'
In ritardo alla festa, ma ho perso molto tempo con questo problema fino a quando non ho trovato la mia risposta.
Breve e dolce, translate
è superiore areplace
. Se sei più interessato alla funzionalità nel tempo, non utilizzare replace
.
Utilizzare anche translate
se non si sa se l'insieme di caratteri da sostituire si sovrappone all'insieme di caratteri utilizzato per sostituire.
Caso in questione:
Usandoti replace
ti aspetteresti ingenuamente che lo snippet "1234".replace("1", "2").replace("2", "3").replace("3", "4")
ritorni "2344"
, ma tornerà di fatto "4444"
.
La traduzione sembra eseguire ciò che OP inizialmente desiderava.
Puoi considerare di scrivere una funzione di escape generica:
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
In questo modo è possibile rendere configurabile la propria funzione con un elenco di caratteri da evitare.
Cordiali saluti, questo è di scarsa utilità per l'OP, ma potrebbe essere utile per altri lettori (per favore non sottovalutare, ne sono consapevole).
Come esercizio un po 'ridicolo ma interessante, volevo vedere se potevo usare la programmazione funzionale di Python per sostituire più caratteri. Sono abbastanza sicuro che questo NON batte solo chiamando due volte (). E se le prestazioni fossero un problema, potresti facilmente battere in ruggine, C, julia, perl, java, javascript e forse anche awk. Utilizza un pacchetto esterno di "aiutanti" chiamato pytoolz , accelerato via cython ( cytoolz, è un pacchetto 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),))))))
Non lo spiegherò nemmeno perché nessuno si preoccuperebbe di usarlo per realizzare la sostituzione multipla. Tuttavia, mi sono sentito in qualche modo realizzato nel fare questo e ho pensato che potesse ispirare altri lettori o vincere un concorso di offuscamento del codice.
Usando riduci che è disponibile in python2.7 e python3. * Puoi facilmente sostituire sottostringhe multiple in modo pulito e pitonico.
# 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 non devi importare ridurre ma in python3. * Devi importarlo dal modulo functools.
Forse un semplice ciclo per i caratteri da sostituire:
a = '&#'
to_replace = ['&', '#']
for char in to_replace:
a = a.replace(char, "\\"+char)
print(a)
>>> \&\#
Cosa ne pensi di questo?
def replace_all(dict, str):
for key in dict:
str = str.replace(key, dict[key])
return str
poi
print(replace_all({"&":"\&", "#":"\#"}, "&#"))
produzione
\&\#
simile alla risposta