Sprawdź, czy istnieje wiele ciągów w innym ciągu

378

Jak mogę sprawdzić, czy którykolwiek z ciągów w tablicy istnieje w innym ciągu?

Lubić:

a = ['a', 'b', 'c']
str = "a123"
if a in str:
  print "some of the strings found in str"
else:
  print "no strings found in str"

Ten kod nie działa, po prostu pokazuje, co chcę osiągnąć.

jahmax
źródło
5
Dziwię się, że nie ma (jeszcze) żadnych odpowiedzi w porównaniu do skompilowanego wyrażenia regularnego pod względem perf, szczególnie w porównaniu z rozmiarem łańcucha i liczbą „igieł” do wyszukania.
Pat
3
@Pat Nie jestem zaskoczony. Pytanie nie dotyczy wydajności. Obecnie większość programistów bardziej zależy na tym, aby to zrobić i na czytelności. Pytanie dotyczące wydajności jest prawidłowe, ale inne pytanie.
guettli
13
Używanie str jako zmiennej jest mylące i może powodować nieoczekiwane zachowanie, ponieważ jest słowem zastrzeżonym; patrz link .
Clever Guy
regex [abc]działa również doskonale i będzie szybszy, jeśli będzie więcej niż kilku kandydatów do przetestowania. Ale jeśli ciągi są dowolne i nie znasz ich wcześniej, aby utworzyć wyrażenie regularne, będziesz musiał zastosować to any(x in str for x in a)podejście.
smci
@CleverGuy Masz rację, choć nie jest to słowo zastrzeżone, w przeciwnym razie nie będziesz mógł do niego przypisać. To jest wbudowane.
wjandrea

Odpowiedzi:

717

Możesz użyć any:

a_string = "A string is more than its parts!"
matches = ["more", "wholesome", "milk"]

if any(x in a_string for x in matches):

Podobnie, aby sprawdzić, czy znaleziono wszystkie ciągi z listy, użyj allzamiast any.

Mark Byers
źródło
11
any () wymaga iteracji. Nie jestem pewien, jakiej wersji Pythona używasz, ale w 2.6 będziesz musiał umieścić [] wokół swojego argumentu na dowolnym (). dowolne ([x w str dla x w a]), dzięki czemu zrozumienie zwraca iterowalną wartość. Ale może nowsze wersje Pythona już to robią.
emispowder
7
@ Mark Byers: Przepraszam za późny komentarz, ale czy istnieje sposób na wydrukowanie znalezionego ciągu? Jak byś to zrobił? Dziękuję Ci.
Shankar Kumar
3
Nie jestem pewien, czy rozumiem, jeśli a to lista, a str to coś, z czym można się równać, jakie jest x? Python newbie ftw. :)
czerwony
2
@red: możesz czytać for x in ajak „dla każdego elementu na liście”. Ponieważ ajest to lista ciągów i xjest elementem tej listy, xjest ciągiem (jeden z „a”, „b”, „c” w oryginalnym przykładzie)
użytkownik
6
@ emispowder Działa dla mnie tak jak jest w Pythonie 2.6.9.
MPlanchard,
67

any()jest zdecydowanie najlepszym podejściem, jeśli wszystko, czego chcesz, to Truelub False, ale jeśli chcesz wiedzieć, który łańcuch / ciągi pasują, możesz użyć kilku rzeczy.

Jeśli chcesz pierwszego dopasowania (z Falsedomyślnie):

match = next((x for x in a if x in str), False)

Jeśli chcesz uzyskać wszystkie dopasowania (w tym duplikaty):

matches = [x for x in a if x in str]

Jeśli chcesz uzyskać wszystkie niedubliczne dopasowania (bez względu na kolejność):

matches = {x for x in a if x in str}

Jeśli chcesz uzyskać wszystkie niedubliczne mecze we właściwej kolejności:

matches = []
for x in a:
    if x in str and x not in matches:
        matches.append(x)
zondo
źródło
dodaj też przykład ostatniego meczu
Oleg Kokorin
@OlegKokorin: Tworzy listę pasujących ciągów w tej samej kolejności, w jakiej je znajduje, ale zachowuje tylko pierwszy, jeśli dwa są takie same.
zondo
Korzystanie z OrderedDictjest prawdopodobnie bardziej wydajne niż lista. Zobacz tę odpowiedź na temat „Usuwanie duplikatów z list”
wjandrea
44

Należy zachować ostrożność, jeśli struny są dłuższe alub strdłuższe. Proste rozwiązania przyjmują O (S * (A ^ 2)), gdzie Sjest długością, stra A jest sumą długości wszystkich łańcuchów a. Aby uzyskać szybsze rozwiązanie, spójrz na algorytm Aho-Corasicka do dopasowywania ciągów, który działa w czasie liniowym O (S + A).

jbernadas
źródło
czy Aho-Corasick może również znaleźć podciągi zamiast przedrostków?
RetroCode,
1
Niektóre biblioteki Pythona Aho-Corasicka są tu i tutaj
vorpal
23

Aby dodać trochę różnorodności dzięki regex:

import re

if any(re.findall(r'a|b|c', str, re.IGNORECASE)):
    print 'possible matches thanks to regex'
else:
    print 'no matches'

lub jeśli twoja lista jest za długa - any(re.findall(r'|'.join(a), str, re.IGNORECASE))

Shankar ARUL - jupyterdata.com
źródło
1
Działa to dla danego przypadku użycia pytania. Jeśli szukasz (lub *to się nie powiedzie, ponieważ należy wykonać cytowanie składni wyrażenia regularnego.
guettli
2
W razie potrzeby możesz uciec '|'.join(map(re.escape, strings_to_match)). Prawdopodobnie re.compile('|'.join(...))również.
Artyer
12

Musisz iterować po elementach.

a = ['a', 'b', 'c']
str = "a123"
found_a_string = False
for item in a:    
    if item in str:
        found_a_string = True

if found_a_string:
    print "found a match"
else:
    print "no match found"
Seamus Campbell
źródło
2
Tak, wiedziałem, jak to zrobić, ale w porównaniu z odpowiedzią Marka, to okropny kod.
jahmax
10
Tylko jeśli rozumiesz kod Marka. Problem polegał na tym, że nie badałeś elementów swojej tablicy. Istnieje wiele zwięzłych, pytonicznych sposobów na osiągnięcie tego, co chcesz, co ukryłoby istotę tego, co było nie tak z twoim kodem.
Seamus Campbell
9
Może to być „okropny kod”, ale właśnie to robi dowolna () . Daje to również pasujący ciąg znaków, podczas gdy dowolny () informuje tylko o zgodności.
alldayremix
4

jbernadas wspomniał już o algorytmie Aho-Corasicka w celu zmniejszenia złożoności.

Oto jeden ze sposobów użycia go w Pythonie:

  1. Pobierz aho_corasick.py stąd

  2. Umieść go w tym samym katalogu, co główny plik Python i nazwij go aho_corasick.py

  3. Wypróbuj alrorithm z następującym kodem:

    from aho_corasick import aho_corasick #(string, keywords)
    
    print(aho_corasick(string, ["keyword1", "keyword2"]))

Pamiętaj, że w wyszukiwaniu rozróżniana jest wielkość liter

Domi W
źródło
3
a = ['a', 'b', 'c']
str =  "a123"

a_match = [True for match in a if match in str]

if True in a_match:
  print "some of the strings found in str"
else:
  print "no strings found in str"
mluebke
źródło
1

To zależy od kontekstu, załóżmy, jeśli chcesz sprawdzić pojedynczy dosłownym jak każdy pojedynczy wyraz (A, E, W, .. etc) w wystarczy

original_word ="hackerearcth"
for 'h' in original_word:
      print("YES")

jeśli chcesz zaznaczyć dowolny znak spośród słowa oryginalnego: skorzystaj z

if any(your_required in yourinput for your_required in original_word ):

jeśli chcesz wszystkich danych wejściowych w tym oryginalnym słowie, skorzystaj ze wszystkich prostych

original_word = ['h', 'a', 'c', 'k', 'e', 'r', 'e', 'a', 'r', 't', 'h']
yourinput = str(input()).lower()
if all(requested_word in yourinput for requested_word in original_word):
    print("yes")
Trinadh Koya
źródło
Jaki byłby twój wkład? Potrafię rozpoznać dwie rzeczy: zdanie, w którym czegoś szukam. Szereg słów, których szukam. Ale ty opisujesz trzy zmienne, a ja nie mogę zrozumieć, co to trzecia.
mayid
1

Po prostu więcej informacji o tym, jak uzyskać wszystkie elementy listy dostępne w String

a = ['a', 'b', 'c']
str = "a123" 
list(filter(lambda x:  x in str, a))
Nilesh Birari
źródło
1

Zaskakująco szybkie podejście polega na użyciu set:

a = ['a', 'b', 'c']
str = "a123"
if set(a) & set(str):
    print("some of the strings found in str")
else:
    print("no strings found in str")

Działa to, jeśli anie zawiera wartości wieloznakowych (w takim przypadku należy użyć, anyjak podano powyżej ). Jeśli tak, to prościej określić ajako ciąg: a = 'abc'.

Berislav Lopac
źródło
0
flog = open('test.txt', 'r')
flogLines = flog.readlines()
strlist = ['SUCCESS', 'Done','SUCCESSFUL']
res = False
for line in flogLines:
     for fstr in strlist:
         if line.find(fstr) != -1:
            print('found') 
            res = True


if res:
    print('res true')
else: 
    print('res false')

przykładowy obraz wyjściowy

LeftSpace
źródło
0

Użyłbym tego rodzaju funkcji do prędkości:

def check_string(string, substring_list):
    for substring in substring_list:
        if substring in string:
            return True
    return False
Iwan Michajłow
źródło
0
data = "firstName and favoriteFood"
mandatory_fields = ['firstName', 'lastName', 'age']


# for each
for field in mandatory_fields:
    if field not in data:
        print("Error, missing req field {0}".format(field));

# still fine, multiple if statements
if ('firstName' not in data or 
    'lastName' not in data or
    'age' not in data):
    print("Error, missing a req field");

# not very readable, list comprehension
missing_fields = [x for x in mandatory_fields if x not in data]
if (len(missing_fields)>0):
    print("Error, missing fields {0}".format(", ".join(missing_fields)));
Robert I.
źródło