How to use Boolean OR inside a regex
<p>I want to use a regex to find a substring, followed by a variable number of characters, followed by any of several substrings.</p>

<p>an re.findall of</p>

<pre><code>"ATGTCAGGTAAGCTTAGGGCTTTAGGATT"
</code></pre>

<p>should give me:</p>

<pre><code>['ATGTCAGGTAA', 'ATGTCAGGTAAGCTTAG', 'ATGTCAGGTAAGCTTAGGGCTTTAG']
</code></pre>

<p>I have tried all of the following without success:</p>

<pre><code>import re
string2 = "ATGTCAGGTAAGCTTAGGGCTTTAGGATT"
re.findall('(ATG.*TAA)|(ATG.*TAG)', string2)
re.findall('ATG.*(TAA|TAG)', string2)
re.findall('ATG.*((TAA)|(TAG))', string2)
re.findall('ATG.*(TAA)|(TAG)', string2)
re.findall('ATG.*(TAA)|ATG.*(TAG)', string2)
re.findall('(ATG.*)(TAA)|(ATG.*)(TAG)', string2)
re.findall('(ATG.*)TAA|(ATG.*)TAG', string2)
</code></pre>

<p>What am I missing here?</p>

<p>I like the accepted answer just fine :-)  That is, I'm adding this for info, not looking for points.</p>

<p>If you have heavy need for this, trying a match on <code>O(N^2)</code> pairs of indices may soon become unbearably slow.  One improvement is to use the <code>.search()</code> method to "leap" directly to the only starting indices that can possibly pay off.  So the following does that.</p>

<p>It also uses the <code>.fullmatch()</code> method so that you don't have to artificially change the "natural" regexp (e.g., in your example, no need to add a trailing <code>$</code> to the regexp - and, indeed, in the following code doing so would no longer work as intended).  Note that <code>.fullmatch()</code> was added in Python 3.4, so this code also requires Python 3!</p>

<p>Finally, this intends to generalize the <code>re</code> module's <code>finditer()</code> function/method.  While you don't need match objects (you just want strings), they're far more generally applicable, and returning a generator is often friendlier than returning a list too.</p>

<p>So, no, this doesn't do exactly what you want, but does things from which you can <em>get</em> what you want, in Python 3, faster:</p>

<pre><code>def finditer_overlap(regexp, string):
    start = 0
    n = len(string)
    while start &lt;= n:
        # don't know whether regexp will find shortest or
        # longest match, but _will_ find leftmost match
        m = regexp.search(string, start)
        if m is None:
            return
        start = m.start()
        for finish in range(start, n+1):
            m = regexp.fullmatch(string, start, finish)
            if m is not None:
                yield m
        start += 1
</code></pre>

<p>Then, e.g.,</p>

<pre><code>import re
string2 = "ATGTCAGGTAAGCTTAGGGCTTTAGGATT"
pat = re.compile("ATG.*(TAA|TAG)")
for match in finditer_overlap(pat, string2):
    print(match.group())
</code></pre>

<p>prints what you wanted in your example.  The other ways you tried to write a regexp should also work.  In this example it's faster because the second time around the outer loop <code>start</code> is 1, and <code>regexp.search(string, 1)</code> fails to find another match, so the generator exits at once (so skips checking <code>O(N^2)</code> other index pairs).</p>

python regex parsing boolean-logic