Python 3+ 是否可以在使用切换器中替换 if in 和 elif
Python 3+ Is It Possible to Replace if in and elif in Using a Switcher
我知道如何在 Python 中使用字典作为切换器。我不确定如何针对我的具体情况使用一个。我想我只需要使用 if、elif 和 else,但希望社区证明我是错误的 :)
我想为字符串中的某些字符创建一个 find/replace 函数。该字符串至少是一个句子,但通常更多,由许多单词组成。
基本上我正在做的是:
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
.....等等
我唯一能想到的就是将字符串拆分成单独的子字符串,然后遍历它们,然后字典切换器就可以工作了。但这显然会增加很多额外的处理时间,使用字典切换器的目的是为了节省时间。
我到处搜索都找不到关于这个特定主题的任何内容。
有没有办法使用 if in 和 elif in 在 Python 中使用切换器?
这是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'}
不是。
尽管本杰明的回答可能是正确的,但它是针对具体情况的,而您的问题具有相当普遍的语气。有一种通用的功能方法(我添加了 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
),因为将使用具有匹配谓词的第一个动作。
只是为了证明正则表达式是一个有效的解决方案,一些时间安排:
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--------
Timings(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 中使用字典作为切换器。我不确定如何针对我的具体情况使用一个。我想我只需要使用 if、elif 和 else,但希望社区证明我是错误的 :)
我想为字符串中的某些字符创建一个 find/replace 函数。该字符串至少是一个句子,但通常更多,由许多单词组成。
基本上我正在做的是:
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
.....等等
我唯一能想到的就是将字符串拆分成单独的子字符串,然后遍历它们,然后字典切换器就可以工作了。但这显然会增加很多额外的处理时间,使用字典切换器的目的是为了节省时间。
我到处搜索都找不到关于这个特定主题的任何内容。
有没有办法使用 if in 和 elif in 在 Python 中使用切换器?
这是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'}
不是。
尽管本杰明的回答可能是正确的,但它是针对具体情况的,而您的问题具有相当普遍的语气。有一种通用的功能方法(我添加了 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
),因为将使用具有匹配谓词的第一个动作。
只是为了证明正则表达式是一个有效的解决方案,一些时间安排:
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--------
Timings(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)