Python-Platzhaltersuche in Zeichenfolge

77

Nehmen wir an, ich habe eine Liste

list = ['this','is','just','a','test']

Wie kann ich einen Benutzer eine Platzhaltersuche durchführen lassen?

Suchwort: 'th_s'

Würde "dies" zurückgeben

Austin
quelle

Antworten:

55

Reguläre Ausdrücke sind wahrscheinlich die einfachste Lösung für dieses Problem:

import re
regex = re.compile('th.s')
l = ['this', 'is', 'just', 'a', 'test']
matches = [string for string in l if re.match(regex, string)]
Yuushi
quelle
7
Diese Antwort sollte nicht akzeptiert werden (Regex verarbeitet keine Wildcard-Übereinstimmungen) - z. B. suche ich nach einer reinen Wildcard-Lösung (von @phihag) und bin bereits mit Regex vertraut
Jirislav
10
Wie verarbeitet Regex keine Platzhalter-Übereinstimmungen?
John Ktejik
158

Verwendung fnmatch:

import fnmatch
lst = ['this','is','just','a','test']
filtered = fnmatch.filter(lst, 'th?s')

Wenn Sie _als Platzhalter zulassen möchten , ersetzen Sie einfach alle Unterstriche durch '?'(für ein Zeichen) oder *(für mehrere Zeichen).

Wenn Sie möchten, dass Ihre Benutzer noch leistungsfähigere Filteroptionen verwenden, sollten Sie ihnen erlauben, reguläre Ausdrücke zu verwenden .

Phihag
quelle
1
Cool :) Aber ich verstehe, dass es auf Pfade abgestimmt ist. Wird es nicht lustig sein, wenn Schrägstriche vorhanden sind? Unterstützt es auch den **Platzhalter? (e-> Ich habe die Dokumente überprüft - es behandelt Schrägstriche nicht anders und daher ist der **Platzhalter hier nicht einmal erforderlich).
Kos
In der Dokumentation heißt fnmatches "Unix Filename Pattern Matching". Aber ich habe es gerade versucht und es scheint unter Windows zu funktionieren. Ist dieses glückliche undefinierte Verhalten oder wird es fnmatchunter Windows unterstützt?
Cowlinator
1
@cowlinator Die Methode zur Dateinamenübereinstimmung wird als Unix-Dateivergleich bezeichnet, da sie von Unix stammt, jedoch vom Betriebssystem unabhängig ist, genauso wie arabische Ziffern auch in Englisch funktionieren.
Phihag
2

Meinen Sie eine bestimmte Syntax für Platzhalter? *Steht normalerweise für "ein oder mehrere" Zeichen und ?steht für eines.

Der einfachste Weg besteht wahrscheinlich darin, einen Platzhalterausdruck in einen regulären Ausdruck zu übersetzen und diesen dann zum Filtern der Ergebnisse zu verwenden.

Kos
quelle
4
Das fnmatchModul hat eine Funktion, um Platzhalter-Übereinstimmungen in reguläre Ausdrücke zu übersetzen:fnmatch.translate
Peter Wood
0

Dieselbe Idee wie Yuushi bei der Verwendung regulärer Ausdrücke, verwendet jedoch die Findall-Methode in der Bibliothek anstelle eines Listenverständnisses:

import re
regex = re.compile('th.s')
l = ['this', 'is', 'just', 'a', 'test']
matches = re.findall(regex, string)
Farhaan Shaikh
quelle
1
Sie müssen immer noch irgendwie Zeichenfolge von einem Array erhalten.
BartBiczBoży
0

Warum benutzt du nicht einfach die Join-Funktion? In einem regulären Ausdruck findall () oder group () benötigen Sie eine Zeichenfolge, also:

import re
regex = re.compile('th.s')
l = ['this', 'is', 'just', 'a', 'test']
matches = re.findall(regex, ' '.join(l)) #Syntax option 1
matches = regex.findall(' '.join(l)) #Syntax option 2

Mit der Funktion join () können Sie eine Liste in eine Zeichenfolge umwandeln. Das einfache Anführungszeichen vor dem Beitritt wird in die Mitte jeder Zeichenfolge in der Liste eingefügt. Wenn Sie diesen Codeteil ('' .join (l)) ausführen, erhalten Sie Folgendes:

"Dies ist nur ein Test"

Sie können also die Funktion findal () verwenden.

Ich weiß, dass ich 7 Jahre zu spät bin, aber ich habe kürzlich einen Account erstellt, weil ich studiere und andere Leute die gleiche Frage haben könnten. Ich hoffe das hilft dir und anderen.


Update nach @ FélixBrunet Kommentare:

import re
regex = re.compile(r'th.s')
l = ['this', 'is', 'just', 'a', 'test','th','s', 'this is']

matches2=[] #declare a list
for i in range(len(l)): #loop with the iterations = list l lenght. This avoid the first item commented by @Felix
if regex.findall(l[i]) != []: #if the position i is not an empty list do the next line. PS: remember regex.findall() command return a list.
    if l[i]== ''.join(regex.findall(l[i])): # If the string of i position of l list = command findall() i position so it'll allow the program do the next line - this avoid the second item commented by @Félix
        matches2.append(''.join(regex.findall(l[i]))) #adds in the list just the string in the matches2 list

print(matches2)
Michel Soares
quelle
würde diese Lösung nicht brechen, wenn es das Wort "th" und "s" gäbe? (Wenn Sie beitreten, erhalten Sie "th s" mit einer gültigen Übereinstimmung. Wenn in der Liste bereits eine Zeichenfolge mit einem Leerzeichen wie "this is" vorhanden ist, gibt Ihre Lösung "this" zurück, wenn keine vorhanden ist Element in der Liste genau passend. Dies könnte ein Problem sein.
Félix Brunet
@ FélixBrunet, du hast absolut recht! Ich habe einen Code mit einer Schleife geschrieben, die die von Ihnen erwähnten Punkte vermeidet! Wie ich in einem Lernprozess bin, glaube ich, dass dies verbessert werden könnte. Wenn Sie noch etwas hinzuzufügen haben, fallen Sie bitte frei. Vielen Dank.
Michel Soares
-6

Einfache Methode ist versuchen os.system:

import os
text = 'this is text'
os.system("echo %s | grep 't*'" % text)
Harry1992
quelle
10
Also ... was passiert, wenn ich text = "die | rm -rf /" setze?
WoLfulus
Zwei Probleme. Erstens sollten Sie nicht berappen müssen, um eine Funktion auszuführen, die Python gut macht. Zweitens haben nicht alle Betriebssysteme grep.
River-Claire Williamson