tags:

views:

50

answers:

3

I'm using the finditer-function in the re module to match some things and everything is working.

Now I need to find out how many matches I've got, is it possible without looping through the iterator twice? (one to find out the count and then the real iteration)

Edit: As requested, some code:

imageMatches = re.finditer("<img src\=\"(?P<path>[-/\w\.]+)\"", response[2])
<Here I need to get the number of matches>
for imageMatch in imageMatches:
     doStuff

Everything works, I just need to get the number of matches before the loop.

+4  A: 

If you know you will want all the matches, you could use re.findall. It will return a list of all the matches. Then you can just do len(result) for the number of matches.

JoshD
It's important to note that `finditer` and `findall` don't always return the same thing for the same regular expression and the same data. `finditer` matches non-overlapping instances of the regex pattern, while `findall` matches all.
Rafe Kettler
@Rafe Kettler: findall finds non-overlapping. From the documentation: Return all non-overlapping matches of pattern in string, as a list of strings. The string is scanned left-to-right, and matches are returned in the order found.
JoshD
dutt
Okay, I posted my answer anyway. Happy trails.
Rafe Kettler
+1  A: 

If you always need to know the length, and you just need the content of the match rather than the other info, you might as well use re.findall. Otherwise, if you only need the length sometimes, you can use e.g.

matches = re.finditer(...)
...
matches = tuple(matches)

to store the iteration of the matches in a reusable tuple. Then just do len(matches).

Another option, if you just need to know the total count after doing whatever with the match objects, is to use

matches = enumerate(re.finditer(...))

which will return an (index, match) pair for each of the original matches. So then you can just store the first element of each tuple in some variable.

But if you need the length first of all, and you need match objects as opposed to just the strings, you should just do

matches = tuple(re.finditer(...))
intuited
A: 

If you find you need to stick with finditer(), you can simply use a counter while you iterate through the iterator.

Example:

>>> from re import *
>>> pattern = compile(r'.ython')
>>> string = 'i like python jython and dython (whatever that is)'
>>> iterator = finditer(pattern, string)
>>> count = 0
>>> for match in iterator:
        count +=1
>>> count
3

If you need the features of finditer() (not matching to overlapping instances), use this method.

Rafe Kettler
Yea I thought of doing that but due to things in my "doStuff" code won't work without adding a lot of extra code in various places. Thanks for the tip anyway :)
dutt
I would use `for count, match in enumerate(iterator):` in the case of Rafe's code.
Tony Veijalainen
@Tony: thanks, forgot about enumerate. If you do use enumerate, though, it will give you the highest *index*, not the actual number of matches; for that, you'd have to add 1.
Rafe Kettler