Мне нужно заменить некоторые символы следующим образом: & ➔ \&, # ➔ \#,...
Я кодировал следующим образом, но я думаю, что должен быть какой-то лучший способ. Есть намеки?
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!
>>> string="abc&def#ghi"
>>> for ch in ['&','#']:
... if ch in string:
... string=string.replace(ch,"\\"+ch)
...
>>> print string
abc\&def\#ghi
Просто соедините функции 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.
Вы всегда будете добавлять обратную косую черту? Если да, попробуйте
import re
rx = re.compile('([&#])')
# ^^ fill in the characters here.
strs = rx.sub('\\\\\\1', strs)
Это может быть не самый эффективный метод, но я думаю, что это самый простой.
Вы можете рассмотреть возможность создания общей функции эвакуации:
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
Таким образом вы можете настроить свою функцию со списком символов, который должен быть экранирован.
Опоздал на вечеринку, но я потерял много времени на эту проблему, пока не нашел свой ответ.
Короткий и сладкий, translate превосходит replace. Если вас больше интересует функциональность с течением времени, не используйте replace.
Также используйте translate, если вы не знаете, перекрывает ли набор символов, подлежащих замене, набор символов, используемых для замены.
Показательный пример:
Используя replace, вы наивно ожидаете, что фрагмент "1234".replace("1", "2").replace("2", "3").replace("3", "4") вернет "2344", но на самом деле он вернет "4444".
Похоже, что перевод выполняет то, что изначально требовалось.
FYI, это мало или вообще не используется для OP, но может быть полезным для других читателей (пожалуйста, не используйте downvote, я знаю об этом).
Как несколько смешное, но интересное упражнение, хотелось бы посмотреть, могу ли я использовать функциональное программирование на python для замены нескольких символов. Я почти уверен, что это не бит, просто вызывающий replace() дважды. И если производительность была проблемой, вы могли бы легко победить это в ржавчине: C, julia, 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. *, Вы можете легко заменить множественные подстроки чистым и питонным способом.
# 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 = '&#'
>>> print a.replace('&', r'\&')
\&#
>>> print a.replace('#', r'\#')
&\#
>>>
Вы хотите использовать "сырую" строку (обозначенную "r", префиксную заменяющую строку), так как необработанные строки не обрабатывают обратную косую черту специально.