Regex match (\w+) to capture single words delimited by ||| - Python
<p>I am trying to match if there's singe word followed by <code>\s|||\s</code> and then another single word followed by <code>\s|||\s</code> so I'm using this regex:</p>

<pre><code>single_word_regex = r'(\w+)+\s\|\|\|\s(\w+)\s\|\|\|\s.*'
</code></pre>

<p>And when I tried to match this string, the regex matching hangs or take minutes (possibly going into some sort of "deep loop")</p>

<pre><code>&gt;&gt;&gt; import re
&gt;&gt;&gt; import time
&gt;&gt;&gt; single_word_regex = r'(\w+)+\s\|\|\|\s(\w+)\s\|\|\|\s.*'        
&gt;&gt;&gt; x = u'amornratchatchawansawangwong ||| amornratchatchawansawangwong . ||| 0.594819 0.5 0.594819 0.25 ||| 0-0 0-1 ||| 1 1 1 ||| |||'
&gt;&gt;&gt; z = u'amor æ ||| amor . i ||| 0.594819 0.0585231 0.594819 0.0489472 ||| 0-0 0-1 1-2 ||| 2 2 2 ||| |||'
&gt;&gt;&gt; y = u'amor ||| amor ||| 0.396546 0.0833347 0.29741 0.08 ||| 0-0 0-1 ||| 3 4 2 ||| |||'
&gt;&gt;&gt; re.match(single_word_regex, z, re.U)                                              
&gt;&gt;&gt; re.match(single_word_regex, y, re.U)                                          
&lt;_sre.SRE_Match object at 0x105b879c0&gt;
&gt;&gt;&gt; start = time.time(); re.match(single_word_regex, y, re.U); print time.time() - start
9.60826873779e-05
&gt;&gt;&gt; start = time.time(); re.match(single_word_regex, x, re.U); print time.time() - start # It hangs...
</code></pre>

<p><strong>Why is it taking that long?</strong></p>

<p>Is there a better/simpler regex to capture this condition<code>len(x.split(' ||| ')[0].split()) == 1 == len(x.split(' ||| ').split())</code>?</p>

<p>Note that by itself, a <code>r'(\w+)+'</code> pattern will not cause the <a href="http://www.regular-expressions.info/catastrophic.html" rel="nofollow">catastrophic backtracking</a>, it will only be "evil" inside a longer expression and especially when it is placed next to the start of the pattern since in case subsequent subpatterns fail the engine backtracks to this one, and as the 1+ quantifier inside is again quantified with <code>+</code>, that creates a huge amount of possible variations to try before failing. You may have a look at <a href="https://regex101.com/r/6ZOhPi/1" rel="nofollow">your regex demo</a> and click the <em>regex debugger</em> on the left to see example regex engine behavior.</p>

<p>The current regex can be written as </p>

<pre><code>r'^(\w+)\s\|{3}\s(\w+)\s\|{3}\s(.*)'
</code></pre>

<p>See the <a href="https://regex101.com/r/8amfjD/2" rel="nofollow">regex demo</a> where there will be a match if you remove space and <code>.</code> in the second field.</p>

<p><strong>Details</strong>:</p>

<ul>
<li><code>^</code> - start of string (not necessary with <code>re.match</code>)</li>
<li><code>(\w+)</code> - (Group 1) 1+ letters/digits/underscores</li>
<li><code>\s</code> - a whitespace</li>
<li><code>\|{3}</code> - 3 pipe symbols</li>
<li><code>\s(\w+)\s\|{3}\s</code> - see above (<code>(\w+)</code> creates Group 2)</li>
<li><code>(.*)</code> - (Group 3) any 0+ characters other than linebreak characters.</li>
</ul>

python regex loops hang