I recently timed a bunch of regexes for the question "A Regex that will never be matched by anything" (my answer here, see for more information).
However, after my testing I noticed that the regex 'a^'
and 'x^'
took drastically different amounts of time to check, although they should be identical. (It was only by chance that I even switched the character.) These timings are below.
In [1]: import re
In [2]: with open('/tmp/longfile.txt') as f:
...: longfile = f.read()
...:
In [3]: len(re.findall('\n',longfile))
Out[3]: 275000
In [4]: len(longfile)
Out[4]: 24733175
...
In [45]: %timeit re.search('x^',longfile)
6.89 ms ± 31.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [46]: %timeit re.search('a^',longfile)
37.2 ms ± 739 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [47]: %timeit re.search(' ^',longfile)
49.8 ms ± 844 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Online testing (with just the first 50 lines) shows the same behavior (1441880 steps and ~710ms vs only 40858 steps and ~113ms): https://regex101.com/r/AwaHmK/1
What is Python doing here that makes 'a^'
take so much longer than 'x^'
?
Just to see if there was something going on inside timeit
or IPython, I wrote a simple timing function myself, and everything checks out:
In [57]: import time
In [59]: import numpy as np
In [62]: def timing(regex,N=7,n=100):
...: tN = []
...: for i in range(N):
...: t0 = time.time()
...: for j in range(n):
...: re.search(regex,longfile)
...: t1 = time.time()
...: tN.append((t1-t0)/n)
...: return np.mean(tN)*1000, np.std(tN)*1000
...:
In [63]: timing('a^')
Out[63]: (37.414282049451558, 0.33898056279589844)
In [64]: timing('x^')
Out[64]: (7.2061508042471756, 0.22062989840321218)
I also replicated my results outside of IPython, in a standard 3.5.2
shell. So the oddity is not constrained to either IPython or timeit
.