Мне нужно заменить некоторые символы следующим образом: &➔ \&, #➔ \#, ...
Я кодировал следующим образом, но я думаю, что должен быть какой-то лучший способ. Есть намеки?
strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...
Мне нужно заменить некоторые символы следующим образом: &➔ \&, #➔ \#, ...
Я кодировал следующим образом, но я думаю, что должен быть какой-то лучший способ. Есть намеки?
strs = strs.replace('&', '\&')
strs = strs.replace('#', '\#')
...
Ответы:
Я рассчитал все методы в текущих ответах вместе с одним дополнительным.
С входной строки abc&def#ghiи заменяя & -> \ & и # -> \ #, самый быстрый способ был приковать вместе эти замены , как это: text.replace('&', '\&').replace('#', '\#').
Сроки для каждой функции:
Вот функции:
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'\#')
Приурочен так:
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')"
Вот аналогичный код, чтобы сделать то же самое, но с большим количеством символов для выхода (\ `* _ {}> # + -.! $):
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'\$')
Вот результаты для той же входной строки abc&def#ghi:
И с более длинной входной строкой ( ## *Something* and [another] thing in a longer sentence with {more} things to replace$):
Добавляем пару вариантов:
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)
С более коротким вводом:
С более длинным вводом:
Так что я собираюсь использовать baдля удобства чтения и скорости.
По подсказкам хаков в комментариях, одним отличием abи baявляется if c in text:проверка. Давайте проверим их еще на двух вариантах:
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 и 3.6.3 и на компьютере, отличном от предыдущего, поэтому нельзя сравнивать напрямую.
╭────────────╥──────┬───────────────┬──────┬──────────────────╮
│ 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 │
└────────────╨──────┴───────────────┴──────┴──────────────────┘
Мы можем сделать вывод, что:
Те, у кого есть чек, в 4 раза быстрее, чем те, у кого нет чека
ab_with_checkнемного лидирует на Python 3, но ba(с проверкой) имеет большее преимущество на Python 2
Тем не менее, самый большой урок здесь - Python 3 в 3 раза быстрее, чем Python 2 ! Нет большой разницы между самым медленным на Python 3 и самым быстрым на Python 2!
if c in text:необходимым в ba?
1.45 usec per loopи без: 5.3 usec per loop, длинной строки, с: 4.38 usec per loopи без: 7.03 usec per loop. (Обратите внимание, что они не сравнимы напрямую с результатами, приведенными выше, потому что это другая машина и т. Д.)
replaceвызывается только тогда, когда cнаходится textв случае, baкогда она вызывается в каждой итерации в 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)? Разве не string.replace(ch,"\\"+ch)достаточно?
Просто цепочка replaceфункций, как это
strs = "abc&def#ghi"
print strs.replace('&', '\&').replace('#', '\#')
# abc\&def\#ghi
Если замен будет больше, вы можете сделать это в общем виде
strs, replacements = "abc&def#ghi", {"&": "\&", "#": "\#"}
print "".join([replacements.get(c, c) for c in strs])
# abc\&def\#ghi
Вот метод python3, использующий str.translateи str.maketrans:
s = "abc&def#ghi"
print(s.translate(str.maketrans({'&': '\&', '#': '\#'})))
Печататься строка abc\&def\#ghi.
.translate()происходит медленнее, чем три .replace()(с использованием CPython 3.6.4).
replace()себя, но я добавил этот ответ для полноты картины.
'\#'действует? не должно быть r'\#'или '\\#'? Может быть проблема форматирования блока кода, возможно.
Вы всегда собираетесь добавить обратную косую черту? Если так, попробуйте
import re
rx = re.compile('([&#])')
# ^^ fill in the characters here.
strs = rx.sub('\\\\\\1', strs)
Возможно, это не самый эффективный метод, но я думаю, что он самый простой.
r'\\\1'
Опоздал на вечеринку, но я потерял много времени на эту проблему, пока не нашел свой ответ.
Короткий и сладкий, translateпревосходящийreplace . Если вас больше интересует функциональность с течением времени, не используйте оптимизацию replace.
Также используйте, translateесли вы не знаете, перекрывает ли набор заменяемых символов набор символов, используемых для замены.
Дело в точке:
При использовании replaceвы наивно ожидаете, что фрагмент "1234".replace("1", "2").replace("2", "3").replace("3", "4")вернется "2344", но на самом деле он вернется "4444".
Похоже, что перевод выполняет то, что изначально хотел OP.
Вы можете написать общую функцию escape:
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
Таким образом, вы можете сделать вашу функцию настраиваемой со списком символов, которые должны быть экранированы.
К вашему сведению, это мало что значит для ОП, но может быть полезно другим читателям (пожалуйста, не понижайте голос, я знаю об этом).
Как смешное, но интересное упражнение, я хотел посмотреть, смогу ли я использовать функциональное программирование на Python для замены нескольких символов. Я почти уверен, что это НЕ бьет просто вызов replace () дважды. И если производительность была проблемой, вы могли бы легко победить это в ржавчине, C, Джулия, Perl, Java, Javascript и, возможно, даже awk. Он использует внешний пакет помощников, называемый pytoolz , ускоренный через cython ( cytoolz, это пакет 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),))))))
Я даже не собираюсь объяснять это, потому что никто не потрудится использовать это для выполнения множественной замены. Тем не менее, я почувствовал, что достиг этого, и подумал, что это может вдохновить других читателей или выиграть конкурс обфускации кода.
Используя Reduction, который доступен в python2.7 и python3. *, Вы можете легко заменить множественные подстроки чистым и pythonic способом.
# 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 вам не нужно импортировать Reduce, но в Python3. * Вы должны импортировать его из модуля functools.
Может быть, простой цикл для замены символов:
a = '&#'
to_replace = ['&', '#']
for char in to_replace:
a = a.replace(char, "\\"+char)
print(a)
>>> \&\#
Как насчет этого?
def replace_all(dict, str):
for key in dict:
str = str.replace(key, dict[key])
return str
затем
print(replace_all({"&":"\&", "#":"\#"}, "&#"))
вывод
\&\#
похоже на ответ