鉴于我知道较长的字符串不区分大小写匹配,我应该如何从另一个字符串的开头删除一个字符串?
How should I remove one string from the start of another given that I know the longer string matches case-insensitively?
假设我有一个工作流程,其中涉及检查长字符串(例如 LS
)的开头,以查看它是否以较短的字符串 SS
开头。如果是这样,我会砍掉 LS
的匹配部分,并对剩余部分做一些处理。否则,我会做其他事情。 (提出这个问题的具体案例是一个解析库。)
def do_thing(LS, SS):
if (LS.startswith(SS)):
action_on_match(LS[len(SS):])
else:
action_on_no_match()
这很简单。不过,现在假设我想做同样的事情,但这次我希望不区分大小写地匹配字符串。可以测试是否“LS.startswith(SS)
但不区分大小写”。但是当我将它传递给action_on_match()
时,我应该如何确定LS
到"chop off"的多少?像以前一样只使用 len(SS)
是不够的,因为如果我是大写或小写或 casefolding 东西,那么 LS
的匹配前缀的长度可能不是我所期望的:改变字符串的大小写可以改变它的长度。重要的是 LS
传递给 action_on_match()
的部分正是程序接收到的输入(当然是在截止点之后)。
回答者建议使用 lower()
并保留使用 len(SS)
,但这行不通:
Python 3.4.2 (v3.4.2:ab2c023a9432, Oct 6 2014, 22:15:05) [MSC v.1600 32 bit (In
tel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def action_on_match (s): return "Match: %s" % s
...
>>> def action_on_no_match (): return "No match"
...
>>> def do_thing (LS, SS):
... if LS.lower().startswith(SS.lower()):
... return action_on_match(LS[len(SS):])
... else:
... return action_on_no_match()
...
>>> do_thing('i\u0307asdf', '\u0130')
'Match: \u0307asdf'
>>>
这里我们希望看到'Match: asdf'
,但是多了一个字符
只需使用str.lower
,"FOO"
的长度将与"foo".lower()
相同:
LS.lower().startswith(SS.lower())
def do_thing(ls, ss):
if ls.startswith(ss):
action_on_match(ls[len(ss):])
else:
action_on_no_match()
足够简单:
def do_thing(LS, SS):
if LS.lower().startswith(SS.lower()):
action_on_match(LS[len(SS):])
else:
action_on_no_match()
我所做的只是将 LS
和 SS
都小写,然后比较它们。对于非常长的字符串,这将比正则表达式解决方案慢得多,因为它必须先将整个字符串转换为小写。
正则表达式解决方案如下所示:
import re
def do_thing(LS, SS):
if re.match("^%s" % SS, LS, re.I):
action_on_match(LS[len(SS):])
else:
action_on_no_match()
性能
对于超过 1000000 次迭代的短字符串(len(LL)
== 8 个字符):
lower()
方法:0.86s(获胜者)
re
方法:1.91s
对于超过 1000000 次迭代的长字符串(len(LL)
== 600 个字符):
lower()
方法:2.54s
re
方法:1.96s (获胜者)
Unicode 组合字符
对于 unicode 组合字符,数据需要 normalised first. This means converting any precomposed character 成其组成部分。你会发现例如:
>>> '\u0130' == 'I\u0307'
False
>>> normalize("NFD", '\u0130') == normalize("NFD", 'I\u0307')
True
您需要对您的输入执行此规范化过程:
SS = normalize("NFD", SS)
LS = normalize("NFD", LS)
假设我有一个工作流程,其中涉及检查长字符串(例如 LS
)的开头,以查看它是否以较短的字符串 SS
开头。如果是这样,我会砍掉 LS
的匹配部分,并对剩余部分做一些处理。否则,我会做其他事情。 (提出这个问题的具体案例是一个解析库。)
def do_thing(LS, SS):
if (LS.startswith(SS)):
action_on_match(LS[len(SS):])
else:
action_on_no_match()
这很简单。不过,现在假设我想做同样的事情,但这次我希望不区分大小写地匹配字符串。可以测试是否“LS.startswith(SS)
但不区分大小写”。但是当我将它传递给action_on_match()
时,我应该如何确定LS
到"chop off"的多少?像以前一样只使用 len(SS)
是不够的,因为如果我是大写或小写或 casefolding 东西,那么 LS
的匹配前缀的长度可能不是我所期望的:改变字符串的大小写可以改变它的长度。重要的是 LS
传递给 action_on_match()
的部分正是程序接收到的输入(当然是在截止点之后)。
回答者建议使用 lower()
并保留使用 len(SS)
,但这行不通:
Python 3.4.2 (v3.4.2:ab2c023a9432, Oct 6 2014, 22:15:05) [MSC v.1600 32 bit (In
tel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def action_on_match (s): return "Match: %s" % s
...
>>> def action_on_no_match (): return "No match"
...
>>> def do_thing (LS, SS):
... if LS.lower().startswith(SS.lower()):
... return action_on_match(LS[len(SS):])
... else:
... return action_on_no_match()
...
>>> do_thing('i\u0307asdf', '\u0130')
'Match: \u0307asdf'
>>>
这里我们希望看到'Match: asdf'
,但是多了一个字符
只需使用str.lower
,"FOO"
的长度将与"foo".lower()
相同:
LS.lower().startswith(SS.lower())
def do_thing(ls, ss):
if ls.startswith(ss):
action_on_match(ls[len(ss):])
else:
action_on_no_match()
足够简单:
def do_thing(LS, SS):
if LS.lower().startswith(SS.lower()):
action_on_match(LS[len(SS):])
else:
action_on_no_match()
我所做的只是将 LS
和 SS
都小写,然后比较它们。对于非常长的字符串,这将比正则表达式解决方案慢得多,因为它必须先将整个字符串转换为小写。
正则表达式解决方案如下所示:
import re
def do_thing(LS, SS):
if re.match("^%s" % SS, LS, re.I):
action_on_match(LS[len(SS):])
else:
action_on_no_match()
性能
对于超过 1000000 次迭代的短字符串(len(LL)
== 8 个字符):
lower()
方法:0.86s(获胜者)re
方法:1.91s
对于超过 1000000 次迭代的长字符串(len(LL)
== 600 个字符):
lower()
方法:2.54sre
方法:1.96s (获胜者)
Unicode 组合字符
对于 unicode 组合字符,数据需要 normalised first. This means converting any precomposed character 成其组成部分。你会发现例如:
>>> '\u0130' == 'I\u0307'
False
>>> normalize("NFD", '\u0130') == normalize("NFD", 'I\u0307')
True
您需要对您的输入执行此规范化过程:
SS = normalize("NFD", SS)
LS = normalize("NFD", LS)