Несколько символов заменить на Python



мне нужно заменить некоторые символы следующим образом: & ->&,# ->#, ...



я закодировал следующим образом, но я думаю, что должен быть какой-то лучший способ. Какие-нибудь намеки?



strs = strs.replace('&', '&')
strs = strs.replace('#', '#')
...
1148   9  

9 ответов:

замена двух символов

я рассчитал все методы в текущих ответах вместе с одним дополнительным.

С входной строкой abc&def#ghi и замена & - > \ & и # ->#, самым быстрым было связать вместе замены, такие как: text.replace('&', '\&').replace('#', '\#').

тайминги для каждой функции:

  • a) 1000000 петель, лучше всего 3: 1.47 МКС на петлю
  • b) 1000000 петель, лучше всего 3: 1.51 МКС на петлю
  • С) 100000 циклы, лучше всего 3: 12,3 МКС на петлю
  • d) 100000 петель, лучше всего 3: 12 МКС на петлю
  • e) 100000 петель, лучше всего 3: 3,27 МКС на петлю
  • f) 1000000 петель, лучше всего 3: 0.817 МКС на петлю
  • g) 100000 петель, лучше всего 3: 3,64 МКС на петлю
  • h) 1000000 петель, лучше всего 3: 0.927 МКС на петлю
  • i) 1000000 петель, лучше всего 3: 0.814 МКС на петлю

здесь есть функции:

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'\', text)


RX = re.compile('([&#])')
def d(text):
    text = RX.sub(r'\', 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')"

замена 17 символов

вот аналогичный код, чтобы сделать то же самое, но с большим количеством символов, чтобы избежать (\`*_{}>#+-.!$):

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'\', text)


RX = re.compile('([\`*_{}[]()>#+-.!$])')
def d(text):
    text = RX.sub(r'\', 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:

  • a) 100000 петель, лучше всего 3: 6.72 МКС на петлю
  • b) 100000 петель, лучше всего 3: 2.64 МКС на петлю
  • c) 100000 петель, лучше всего 3: 11,9 МКС на петлю
  • d) 100000 петель, лучше всего 3: 4,92 МКС на петлю
  • e) 100000 петель, лучше всего 3: 2.96 МКС на петлю
  • f) 100000 петель, лучше всего 3: 4,29 МКС на петлю
  • g) 100000 петель, лучше всего 3: 4,68 МКС на петлю
  • h) 100000 петель, лучше всего 3: 4,73 МКС на петлю
  • i) 100000 петель, лучше всего 3: 4,24 МКС на петлю

и с более длинной входной строки (## *Something* and [another] thing in a longer sentence with {more} things to replace$):

  • a) 100000 петель, лучше всего 3: 7.59 МКС на петлю
  • b) 100000 петель, лучше всего 3: 6.54 МКС на петлю
  • c) 100000 петель, лучше всего 3: 16,9 МКС на петлю
  • d) 100000 петель, лучше всего 3: 7,29 МКС на петлю
  • e) 100000 петель, лучше всего 3: 12,2 МКС на петлю
  • f) 100000 петель, лучше всего 3: 5.38 МКС на петлю
  • g) 10000 петель, лучше всего 3: 21.7 МКС в петля
  • h)100000 петель, лучше всего 3: 5.7 МКС на петлю
  • i) 100000 петель, лучше всего 3: 5.13 МКС на петлю

добавление нескольких вариантов:

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)

С более коротким входом:

  • ab) 100000 петель, лучше всего 3: 7,05 МКС на петлю
  • ba) 100000 петель, лучше всего 3: 2,4 МКС на петлю

С более вход:

  • ab) 100000 петель, лучше всего 3: 7,71 МКС на петлю
  • ba) 100000 петель, лучше всего 3: 6.08 МКС на петлю

так что я собираюсь использовать ba для удобочитаемости и скорости.

дополнительное соглашение

подсказано haccks в комментариях, одна разница между 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

вы всегда будете добавлять обратную косую черту? Если да, то попробуйте

import re
rx = re.compile('([&#])')
#                  ^^ fill in the characters here.
strs = rx.sub('\\\1', strs)

может быть, это не самый эффективный метод, но я думаю, что это самый простой.

вот метод python3 с использованием str.translate и str.maketrans:

s = "abc&def#ghi"
print(s.translate(str.maketrans({'&': '\&', '#': '\#'})))

печатная строка abc\&def\#ghi.

вы можете рассмотреть возможность написания общей функции 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

таким образом, вы можете настроить свою функцию со списком символов, которые должны быть экранированы.

FYI, это мало или нет пользы для OP, но это может быть полезно для других читателей (пожалуйста, не понижайте голос, я знаю об этом).

как несколько смешное, но интересное упражнение, хотел посмотреть, могу ли я использовать функциональное программирование python для замены нескольких символов. Я уверен, что это не бьет просто вызов replace() дважды. И если бы производительность была проблемой, вы могли бы легко победить это в rust, 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),))))))

Я даже не собираюсь объяснять это, потому что никто не потрудился бы использовать это для выполнения нескольких замен. Тем не менее, я чувствовал себя несколько опытным в этом и думал, что это может вдохновить других читателей или выиграть конкурс обфускации кода.

>>> a = '&#'
>>> print a.replace('&', r'\&')
\&#
>>> print a.replace('#', r'\#')
&\#
>>> 

вы хотите использовать "сырую" строку (обозначенную префиксом " r " заменяющей строки), так как необработанные строки не обрабатывают обратную косую черту специально.

используя reduce, который доступен в python2. 7 и python3.* вы можете легко заменить нескольких подстрок в чистые и подходящие для Python путь.

# 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.

Comments

    Ничего не найдено.