Можно ли заменить Python 3+, если в и elif в Использование Switcher
Я знаю, как использовать словарь в качестве переключателя в Python. Я не уверен, как использовать один для моего конкретного случая. Я думаю, что мне просто нужно будет использовать if, elif, и еще, но, надеюсь, сообщество оказалось неправым:)
Я хочу сделать функцию поиска / замены для определенных символов в строках. Строка, по крайней мере, одно предложение, но обычно больше и состоит из многих слов.
В основном я делаю следующее:
if non-breaking hyphen in string: # string is a sentence with many words
replace non-breaking hyphen with dash
elif en dash in string:
replace en dash with dash
elif em dash in string:
replace em dash with dash
elif non-breaking space in string:
replace non-breaking space with space
.... и так далее
Единственное, о чем я могу думать, - это разбить строку на отдельные подстроки, а затем зациклить их, чтобы сработал переключатель словаря. Но это, очевидно, добавило бы много дополнительного времени обработки, и цель использования словарного переключателя - сэкономить время.
Я не мог найти что-либо на эту конкретную тему поиска везде.
Есть ли способ использовать переключатель в Python, используя if in и elif in?
3 ответа
Вот str.translate
решение
replacements = {
'\u2011': '-', # non breaking hyphen
'\u2013': '-', # en dash
'\u2014': '-', # em dash
'\u00A0': ' ', # nbsp
}
trans = str.maketrans(replacements)
new_string = your_string.translate(trans)
Обратите внимание, что это работает, только если вы хотите заменить отдельные символы из ввода. {'a': 'bb'}
является действительным replacements
, но {'bb': 'a'}
не является.
Просто чтобы показать, что регулярное выражение является допустимым решением, и некоторые моменты времени:
replacements = {
'\u2011': '-',
'\u2013': '-',
'\u2014': '-',
'\u00A0': ' ',
}
import re
s = "1‑‑‑‑2–––––––3————————"
re.sub(
'|'.join(re.escape(x) for x in replacements),
lambda x: replacements[x.group()], s
)
# Result
1----2-------3--------
Сроки (str.trans
побеждает и тоже чище)
s = "1‑‑‑‑2–––––––3————————"
s *= 10000
%timeit re.sub('|'.join(re.escape(x) for x in replacements), lambda x: replacements[x.group()], s)
90.7 ms ± 182 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [733]: %timeit s.translate(trans)
15.8 ms ± 59.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Хотя ответ Бенджамина может быть правильным, он зависит от конкретного случая, в то время как ваш вопрос имеет довольно общий тон. Существует универсальный функциональный подход (я добавил аннотации типа Python 3.5, чтобы сделать этот код понятным):
from typing import TypeVar, Callable, Iterable
A = TypeVar('A')
B = TypeVar('B')
Predicate = Callable[[A], bool]
Action = Callable[[A], B]
Switch = Tuple[Predicate, Action]
def switch(switches: Iterable[Switch], default: B, x: A) -> B:
return next(
(act(x) for pred, act in switches if pred(x)), default
)
switches = [
(lambda x: '\u2011' in x, lambda x: x.replace('\u2011', '-')),
(lambda x: '\u2013' in x, lambda x: x.replace('\u2013', '-'))
]
a = "I'm–a–string–with–en–dashes"
switch(switches, a, a) # if no switches are matched, return the input
Это довольно излишне в вашем случае, потому что ваш пример сводится к операции регулярного выражения. Принять к сведению, в то время как switches
может быть любым итеративным, вы можете использовать что-то с предсказуемым порядком итерации, т.е. Sequence
тип (например list
или же tuple
), потому что будет использовано первое действие с соответствующим предикатом.