2015-02-24 35 views
0

假設我有一個涉及檢查長字符串(例如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)但不區分大小寫」。但是,我應該如何確定LS當我將它傳遞給action_on_match()時「砍掉」多少?僅僅使用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',但有一個多餘的字符。

+1

'改變一個字符串的情況下,可以改變其length':你能更多地討論這..? – 2015-02-24 15:50:59

+0

@mu,U + 00DF LATIN SMALL LETTER SHARP S轉換爲大寫字母時變爲「SS」。 U + 0130拉丁大寫字母I變成小寫字母時,變成兩個字符(U + 0069拉丁小字母I和U + 0307合併字母)。 – Hammerite 2015-02-24 16:13:06

+0

這是蟒蛇2還是3? – 2015-02-24 16:19:20

回答

3

簡單:

def do_thing(LS, SS): 
    if LS.lower().startswith(SS.lower()): 
     action_on_match(LS[len(SS):]) 
    else: 
     action_on_no_match() 

我做的是低殼體內都LSSS,然後比較它們。對於很長的字符串,這會比正則表達式解決方案慢得多,因爲它必須先將整個字符串轉換爲小寫字母。

甲正則表達式的解決方案將是這樣的:

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() 

性能

對於短字符串(len(LL) == 8個字符)超過百萬次迭代:

  • lower()方法:0.86 s (獲勝者)
  • re方法:1.91s

對於長串(len(LL) == 600個字符)超過百萬次迭代:

  • lower()方法:2.54s
  • re方法:1。96S (優勝者)

的Unicode組合字符

對於Unicode組合字符,所述數據需要normalised第一。這意味着將任何precomposed character轉換爲其組成部分。你會發現,例如:

>>> '\u0130' == 'I\u0307' 
False 
>>> normalize("NFD", '\u0130') == normalize("NFD", 'I\u0307') 
True 

您需要在您的輸入執行此正常化進程:

SS = normalize("NFD", SS) 
LS = normalize("NFD", LS) 
+0

請參閱我編輯的問題,爲什麼您對do_thing()的修改不起作用。 – Hammerite 2015-02-24 16:10:19

+0

@Hammerite查看我的更新 – 2015-02-24 17:27:00

0

只需使用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() 
相關問題