2012-11-01 21 views
5

Łańcuchy w języku Python mają metodę find ("somestring"), która zwraca numer indeksu dla "somestring" w ciągu znaków.Jak mogę znaleźć pierwsze wystąpienie podciągu występującego po innym podciągu w pythonie?

Ale powiedzmy, że mam ciąg jak poniżej:

"5 $ 7 $ 9 $ Całkowity koszt: $ $ 35 14"

I chcę, aby znaleźć indeks pierwszego wystąpienia '$', który występuje po ciąg "Całkowity koszt" - Chciałbym móc powiedzieć Pythonowi, wyszukać '$', zaczynając od numeru indeksu dla "Całkowitego kosztu", i zwrócić numer indeksu (w odniesieniu do całego ciągu znaków) za pierwsze wystąpienie "$", które znajdziesz. Metoda find() zwróciłaby 0, a funkcja rfind() również nie działałaby w tym przypadku.

Jeden rodzaj kludgy sposób to zrobić jest następujący:

def findStrAfterStr(myString, searchText, afterText): 

    splitString = myString.split(afterText) 
    myIndex = len(splitString[0]) + len(afterText) + splitString[1].find(searchText) 
    return myIndex 

myString = "$5 $7 $9  Total Cost: $35 $14" 
searchText = "$" 
afterText = "Total Cost" 

findStrAfterStr(myString, searchText, afterText) 

Ale wydaje się, że powinien być łatwiejszy sposób, aby to zrobić, i zakładam prawdopodobnie istnieje, a ja po prostu nie wiem co to jest. Myśli?

Byłoby to szczególnie przydatne do krojenia, gdy znajdę się robi to dużo:

myString[myString.find("startingSubstr"):myString.find("endingSubstr")] 

i naturalnie chcę „endingSubstr” być tym, który występuje po „startingSubstr”.

+0

Należy użyć wyrażenia regularnego. Czy naprawdę potrzebujesz miejsca na $, lub po prostu potrzebujesz dowiedzieć się o ilości pieniędzy? – lolopop

+0

Jestem trochę regex n00b - jak to zrobić z wyrażeniem regularnym? – CQP

+0

Jeszcze raz, czego potrzebujesz? – lolopop

Odpowiedz

11

użyć opcjonalnego drugiego argumentu str.find:

def findStrAfterStr(myString, searchText, afterText): 
    after_index = myString.index(afterText) 
    return myString.find(searchText, after_index) 

Albo, jak sugeruje pythonm, można użyj wyrażeń regularnych.

polecam „nie Naprawdę trzeba” podejście do wyrażeń regularnych, bo to często tak trudno zrozumieć, co robi kod kiedy ją ponownie przeczytać później. Odkryłem też, że w większości przypadków można zrobić to samo bez wyrażeń regularnych i uzyskać kod, który jest łatwiejszy do odczytania w ramach umowy. Porównaj:

import re 

def findStrAfterStr(myString, searchText, afterText): 
    pattern = "{0}.*?({1})".format(re.escape(afterText), re.escape(searchText)) 
    match = re.search(pattern, myString) 
    return match.start(1) if match else -1 
+0

Dzięki, właśnie to chciałem ... – CQP

+0

+1 dla argumentu "str.find" 2. Prawdopodobnie chcesz wrzucić 're.escape' dla' re.szukaj' (zwłaszcza, że ​​przykład używa '$') –

+1

@Jon Tak, doszedłem do tego samego wniosku. Musiałem również użyć nieagrypcyjnego modyfikatora do '. *'. –

3
def findStrAfter(myString, searchText, afterText): 
    try: 
     i = myString.index(afterText) 
     return min(i for i,char in enumerate(myString) if myString[i:].startswith(searchText) and i>afterText) 
    except ValueError: 
     print "'%s' does not exist" %afterText 

OR (efektywniej):

def findStrAfter(myString, searchText, afterText): 
    try: 
     i = myString.index(afterText) 
    except ValueError: 
     print "'%s' does not exist" %afterText 
     raise 
    try: 
     return myString[i:].index(searchText) 
    except ValueError: 
     print "'%s' does not exist after '%s' in myString" %(searchText, afterText) 
     raise 

Nadzieja to pomaga

1

co z tym?

return string.index('Total Cost:') + string[string.index('Total Cost:'):].index('$') 

LUB

i = string.index('Total Cost:') 
return i + string[i:].index('$') 
Powiązane problemy