104

Lets say that I have a list

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

how can I have a user do a wildcard search?

Search Word: 'th_s'

Would return 'this'

Austin
  • 4,296
  • 6
  • 40
  • 52

6 Answers6

204

Use fnmatch:

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

If you want to allow _ as a wildcard, just replace all underscores with '?' (for one character) or * (for multiple characters).

If you want your users to use even more powerful filtering options, consider allowing them to use regular expressions.

phihag
  • 278,196
  • 72
  • 453
  • 469
  • 1
    Cool :) But I understand that is it tuned to match paths, won't it act funny if slashes are present? Also, does it support the `**` wildcard? (e-> I've checked the docs- it doesn't treat slashes differently and so the `**` wildcard isn't even necessary here). – Kos Jul 11 '12 at 07:00
  • The documentation states that `fnmatch` is "Unix filename pattern matching". But I just tried it, and it seems to work on Windows. Is this lucky undefined behavior, or is `fnmatch` supported on Windows? – cowlinator Feb 07 '20 at 23:33
  • 2
    @cowlinator The method of filename matching is called _Unix file matching_ because it originated with Unix, but it is operating system-independent, in the same way that arabic numerals also work in English. – phihag Feb 09 '20 at 20:04
  • The filter just works with lists as argument. In case of string I need a re. – Timo Jan 06 '21 at 12:51
  • 1
    @Timo You can try `fnmatch.fnmatch` or `fnmatch.fnmatchcase` which accept string as first param – konchy Feb 01 '23 at 02:59
62

Regular expressions are probably the easiest solution to this 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
  • 25,132
  • 7
  • 63
  • 81
  • 15
    This shouldn't be accepted answer (regex doesn't process wildcard matches) - e.g. I'm looking for pure wildcard solution (given by @phihag) and I'm already familiar with regex – jirislav Oct 16 '17 at 07:02
  • 12
    how does regex not process wildcard matches?? – john k Nov 26 '17 at 22:30
0

Do you mean any specific syntax for wildcards? Usually * stands for "one or many" characters and ? stands for one.

The simplest way probably is to translate a wildcard expression into a regular expression, then use that for filtering the results.

Kos
  • 70,399
  • 25
  • 169
  • 233
  • 5
    The `fnmatch` module has a function to translate wildcard matches into regular expressions: [**`fnmatch.translate`**](https://docs.python.org/2/library/fnmatch.html#fnmatch.translate) – Peter Wood Mar 07 '16 at 03:12
  • It seems that * is for zero to more, at least it works for me because I need a string that sometimes has NOT the searched char.. – Timo Jan 06 '21 at 12:52
0

Same idea as Yuushi in using regular expressions, but this uses the findall method within the re library instead of a list comprehension:

import re
regex = re.compile('th.s')
l = ['this', 'is', 'just', 'a', 'test']
matches = re.findall(regex, string)
Farhaan S.
  • 104
  • 5
0

Why don't you just use the join function? In a regex findall() or group() you will need a string so:

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

The join() function allows you to transform a list in a string. The single quote before join is what you will put in the middle of each string on list. When you execute this code part (' '.join(l)) you'll receive this:

'this is just a test'

So you can use the findal() function.

I know i am 7 years late, but i recently create an account because I'm studying and other people could have the same question. I hope this help you and others.


Update After @FélixBrunet comments:

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)
  • would not this solution break if there was the word "th" and "s"? (by joining, you would get "th s", with would be a valid match. also, if there was already in the list a string with space like "this is", your solution would return "this" event it there was no element in the list exacly fitting. this could be a problem. – Félix Brunet Oct 17 '19 at 18:06
  • @FélixBrunet, you are absolutely right! I wrote a code with a loop that avoid the itens you have mentioned! How I'm in a learning process, I believe this could be improved. If you have something more to add, please fell free. Thank You. – Michel Soares Oct 18 '19 at 21:11
-11

Easy method is try os.system:

import os
text = 'this is text'
os.system("echo %s | grep 't*'" % text)
Buddy
  • 10,874
  • 5
  • 41
  • 58
Harry1992
  • 453
  • 1
  • 5
  • 12