2012-03-08 15 views
6

Mam listę ciągów, z których chcę zlokalizować każdą linię, która ma "http: //" w nim, ale nie ma "lulz", " lmfao ',' .png 'lub dowolne inne pozycje na liście napisów w nim zawartych. Jak bym to zrobił?Jeśli ciąg nie zawiera żadnej listy ciągów w pytonie

Moje instynkty każą mi używać wyrażeń regularnych, ale mam moralny sprzeciw wobec czarów.

Odpowiedz

10

Tutaj jest opcja, że ​​jest dość rozciągliwy jeśli lista ciągów do wykluczenia jest duża:

exclude = ['lulz', 'lmfao', '.png'] 
filter_func = lambda s: 'http://' in s and not any(x in s for x in exclude) 

matching_lines = filter(filter_func, string_list) 

Lista rozumienie alternatywa:

matching_lines = [line for line in string_list if filter_func(line)] 
+0

Awesome! Używam lambda! Wiedziałem, że istnieje z jakiegoś powodu! – directedition

+1

Nie musisz. 'lambda' pozwala ci zdefiniować funkcję inline zamiast ustawiania zmiennej' filter_func'; ale równie dobrze można napisać 'def filter_func (s): return 'http: //' in s, a nie any (x in s for x in exclude)'. Pamiętaj, że funkcje są obiektami. –

+0

Powiedziałbym nawet, że jest to nieodpowiednie użycie 'lambda'. Nie ma powodu, aby preferować go do "def" tutaj. – wim

2

Spróbuj tego:

for s in strings: 
    if 'http://' in s and not 'lulz' in s and not 'lmfao' in s and not '.png' in s: 
     # found it 
     pass 

Inną opcją, jeśli trzeba opcje bardziej elastyczne:

words = ('lmfao', '.png', 'lulz') 
for s in strings: 
    if 'http://' in s and all(map(lambda x, y: x not in y, words, list(s * len(words))): 
     # found it 
     pass 
+0

który został moje pierwsze podejście. Ale gdy moja lista się powiększyła, a linia stała się nieporęczna, miałem nadzieję, że jest lepszy sposób. – directedition

+1

To może wymknąć się spod kontroli, jeśli kiedykolwiek chciał rozszerzyć listę słów stop. Jak zmieniłbyś swoje podejście? Ale wciąż +1 dla prostych rozwiązań. – prelic

3

To prawie równoważne rozwiązania FJ, ale używa generator expressions zamiast wyrażeń lambda i funkcję filtra:

haystack = ['http://blah', 'http://lulz', 'blah blah', 'http://lmfao'] 
exclude = ['lulz', 'lmfao', '.png'] 

http_strings = (s for s in haystack if s.startswith('http://')) 
result_strings = (s for s in http_strings if not any(e in s for e in exclude)) 

print list(result_strings) 

Gdy ten drukuje:

['http://blah'] 
+0

+1 dla generatorów. Zauważ, że możesz to zrobić jako (n prawie) jedno-liniowy: 'result_strings = [s dla s w haystack jeśli s.startswith ('http: //'), a nie any (e w s dla e w exclude)] '. Potrzebny jest podział linii, aby pasował do 80 kolumn (w przypadku większości przewodników stylów), ale uważam, że jest to nieco łatwiejsze do wykonania niż wersja z dwoma generatorami. timeit informuje również, że jest to trochę szybsze, a także nieco szybsze niż wersja filtru F.J. (która, IMO, jest najtrudniejsza do naśladowania z tych trzech). – lvc

Powiązane problemy