Bazı karakterleri şu şekilde değiştirmem gerekiyor: &
➔ \&
, #
➔ \#
, ...
Aşağıdaki gibi kodladım, ama sanırım daha iyi bir yolu olmalı. Herhangi bir ipucu?
strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...
Bazı karakterleri şu şekilde değiştirmem gerekiyor: &
➔ \&
, #
➔ \#
, ...
Aşağıdaki gibi kodladım, ama sanırım daha iyi bir yolu olmalı. Herhangi bir ipucu?
strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...
Yanıtlar:
Mevcut cevaplardaki tüm yöntemleri bir ekstra ile birlikte zamanladım.
Bir giriş dizesi ile abc&def#ghi
ve değiştirme & -> \ & ve # -> \ #, en hızlı şekilde bir araya zincirine böyle değiştirmeler oldu: text.replace('&', '\&').replace('#', '\#')
.
Her işlev için zamanlamalar:
İşte fonksiyonlar:
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'\#')
Şu şekilde zamanlanmış:
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')"
İşte aynısını yapmak için, ancak daha fazla karakterden çıkılacak benzer kod (\ `* _ {}> # + -.! $):
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'\$')
İşte aynı girdi dizesi için sonuçlar abc&def#ghi
:
Ve daha uzun bir girdi dizesiyle ( ## *Something* and [another] thing in a longer sentence with {more} things to replace$
):
Birkaç varyant eklemek:
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)
Daha kısa girişle:
Daha uzun girdi ile:
Bu yüzden ba
okunabilirlik ve hız için kullanacağım .
Arasında bir fark, yorumlardaki haccks tarafından istendiğinde ab
ve ba
bir if c in text:
çek. Onları iki değişkenle daha test edelim:
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)
Python 2.7.14 ve 3.6.3'te ve önceki setten farklı bir makinede döngü başına μs cinsinden süre, bu nedenle doğrudan karşılaştırılamaz.
╭────────────╥──────┬───────────────┬──────┬──────────────────╮
│ 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 │
└────────────╨──────┴───────────────┴──────┴──────────────────┘
Bunu sonuçlandırabiliriz:
Çekli olanlar, çek olmayanlara göre 4 kata kadar daha hızlıdır
ab_with_check
Python 3'te biraz önde, ancak ba
(kontrolle) Python 2'de daha fazla öne çıkıyor
Bununla birlikte, buradaki en büyük ders, Python 3'ün Python 2'den 3 kata kadar daha hızlı olmasıdır ! Python 3'te en yavaş ile Python 2'de en hızlı arasında çok büyük bir fark yoktur!
if c in text:
gerekli ba
mi?
replace
yalnızca denir c
bulunursa text
durumunda ba
bunun her tekrarında denirken 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)
? Sadece mi string.replace(ch,"\\"+ch)
yeterince?
İşte str.translate
ve kullanan bir python3 yöntemi str.maketrans
:
s = "abc&def#ghi"
print(s.translate(str.maketrans({'&': '\&', '#': '\#'})))
Yazdırılan dize abc\&def\#ghi
.
.translate()
üç zincirden daha yavaş görünüyor .replace()
(CPython 3.6.4 kullanarak).
replace()
kendimi kullanırdım ama bu cevabı bütünlük adına ekledim.
Bunun replace
gibi işlevleri basitçe zincirleyin
strs = "abc&def#ghi"
print strs.replace('&', '\&').replace('#', '\#')
# abc\&def\#ghi
Değişimlerin sayısı daha fazla olacaksa, bunu bu genel şekilde yapabilirsiniz.
strs, replacements = "abc&def#ghi", {"&": "\&", "#": "\#"}
print "".join([replacements.get(c, c) for c in strs])
# abc\&def\#ghi
Her zaman bir ters eğik çizgi mi ekleyeceksiniz? Eğer öyleyse, dene
import re
rx = re.compile('([&#])')
# ^^ fill in the characters here.
strs = rx.sub('\\\\\\1', strs)
En verimli yöntem olmayabilir ama bence en kolayı bu.
r'\\\1'
Partiye geç kaldım ama cevabımı bulana kadar bu sorunla çok zaman kaybettim.
Kısa ve tatlıdır, translate
üstündürreplace
. Zaman optimizasyonu içinde işlevsellikle daha fazla ilgileniyorsanız, kullanmayın replace
.
Ayrıca translate
, değiştirilecek karakter kümesinin değiştirmek için kullanılan karakter kümesiyle örtüşüp örtüşmediğini bilmiyorsanız kullanın.
Konuşma konusu olan mesele:
replace
Sizi kullanmak saf bir şekilde pasajın "1234".replace("1", "2").replace("2", "3").replace("3", "4")
geri dönmesini beklersiniz "2344"
, ancak aslında geri dönecektir "4444"
.
Çeviri, başlangıçta istenen OP'yi gerçekleştiriyor gibi görünüyor.
Genel bir kaçış işlevi yazmayı düşünebilirsiniz:
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
Bu şekilde, işlevinizi öncelenmesi gereken bir karakter listesi ile yapılandırılabilir hale getirebilirsiniz.
Bilginize, bu OP için çok az faydalıdır veya hiç faydası yoktur, ancak diğer okuyucular için yararlı olabilir (lütfen olumsuz oy vermeyin, bunun farkındayım).
Biraz saçma ama ilginç bir alıştırma olarak, birden çok karakteri değiştirmek için python işlevsel programlamayı kullanıp kullanamayacağımı görmek istedim. Bunun sadece replace () çağrısını iki kez geçmediğinden eminim. Ve performans bir sorun olsaydı, bunu rust, C, julia, perl, java, javascript ve hatta belki awk ile kolayca yenebilirdiniz. Pytoolz adı verilen ve cython ( cytoolz, bu bir pypi paketi ) ile hızlandırılan harici bir 'yardımcılar' paketi kullanır .
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),))))))
Bunu açıklamayacağım bile çünkü kimse bunu birden fazla değiştirme yapmak için kullanmaya zahmet etmeyecek. Yine de, bunu yaparken bir şekilde başarılı olduğumu hissettim ve diğer okuyuculara ilham verebileceğini veya bir kod gizleme yarışmasını kazanabileceğini düşündüm.
Python2.7 ve python3. * 'Te bulunan indirgeme özelliğini kullanarak çok sayıda alt dizeyi temiz ve pitonik bir şekilde kolayca değiştirebilirsiniz.
# 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"
Python2.7'de indirgeme aktarmanız gerekmez, ancak python3. * 'De onu functools modülünden içe aktarmanız gerekir.
ba
Hugo'nun bahsettiği değişken ):lambda text, ptuple: text.replace(ptuple[0], ptuple[1]) if ptuple[0] in text else text
Belki karakterlerin yerini alacak basit bir döngü:
a = '&#'
to_replace = ['&', '#']
for char in to_replace:
a = a.replace(char, "\\"+char)
print(a)
>>> \&\#
Buna ne dersin?
def replace_all(dict, str):
for key in dict:
str = str.replace(key, dict[key])
return str
sonra
print(replace_all({"&":"\&", "#":"\#"}, "&#"))
çıktı
\&\#
cevaba benzer
Python 3.8 ve üzeri için atama ifadeleri kullanılabilir
(text := text.replace(s, f"\\{i}") for s in "&#" if s in text)
Bununla birlikte, bunun PEP 572'de açıklandığı gibi atama ifadelerinin "uygun kullanımı" olarak kabul edilip edilmeyeceğinden emin değilim , ancak temiz görünüyor ve oldukça iyi okuyor (gözlerime). Tüm ara dizeleri de istiyorsanız bu "uygun" olacaktır. Örneğin, (tüm küçük harfli ünlüleri kaldırarak):
text = "Lorem ipsum dolor sit amet"
intermediates = [text := text.replace(i, "") for i in "aeiou" if i in text]
['Lorem ipsum dolor sit met',
'Lorm ipsum dolor sit mt',
'Lorm psum dolor st mt',
'Lrm psum dlr st mt',
'Lrm psm dlr st mt']
Artı tarafta, kabul edilen cevapta daha hızlı yöntemlerden bazılarından daha hızlı (beklenmedik bir şekilde?) Görünüyor ve hem artan dizi uzunluğu hem de artan sayıda ikame ile güzel bir şekilde çalışıyor gibi görünüyor.
Yukarıdaki karşılaştırmanın kodu aşağıdadır. Hayatımı biraz daha basitleştirmek için rastgele dizeler kullanıyorum ve değiştirilecek karakterler dizenin kendisinden rastgele seçiliyor. (Not: Burada ipython'un% timeit sihrini kullanıyorum, bu yüzden bunu ipython / jupyter'da çalıştırın).
import random, string
def make_txt(length):
"makes a random string of a given length"
return "".join(random.choices(string.printable, k=length))
def get_substring(s, num):
"gets a substring"
return "".join(random.choices(s, k=num))
def a(text, replace): # one of the better performing approaches from the accepted answer
for i in replace:
if i in text:
text = text.replace(i, "")
def b(text, replace):
_ = (text := text.replace(i, "") for i in replace if i in text)
def compare(strlen, replace_length):
"use ipython / jupyter for the %timeit functionality"
times_a, times_b = [], []
for i in range(*strlen):
el = make_txt(i)
et = get_substring(el, replace_length)
res_a = %timeit -n 1000 -o a(el, et) # ipython magic
el = make_txt(i)
et = get_substring(el, replace_length)
res_b = %timeit -n 1000 -o b(el, et) # ipython magic
times_a.append(res_a.average * 1e6)
times_b.append(res_b.average * 1e6)
return times_a, times_b
#----run
t2 = compare((2*2, 1000, 50), 2)
t10 = compare((2*10, 1000, 50), 10)