If you structure it like this, it removes the catastrophic backtracking:
var reg = /^(\w+)( \w+)*&(\w+)( \w+)*$/;
The key is changing (\w+ ?)+
to (\w+)( \w+)*
, so that there is only one way for the string to be parsed for that regular expression. To see the problem in your original expression, let's take a look at the string "number number"
and the expression /(\w+ ?)+/
. Your intention is to have the string broken into "number "
and "number"
by this regular expression, however, /(\w+ ?)/
can also match each letter individually, which makes your expression ambiguous. On the other hand, /(\w+)( \w+)*/
can only match "number number"
in one way, as a space is required at the beginning of each iteration of the second subpattern.
Test it out here:
function testRegExp() {
var rStr = '';
try {
var reg = new RegExp($('#r').val());
rStr += reg.test( $('#t').val() );
} catch( e ) {
rStr = 'regex error';
}
$('#result').val( rStr );
}
$('input').on( 'input', testRegExp );
testRegExp();
label {
width: 80px;
display: inline-block;
}
input#t, input#r {
width: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>
<label>String: </label>
<input id="t" type="text" value="number number number number number number number&" /></p>
<p><label>RegExp: </label>
<input id="r" type="text" value="^(\w+)( \w+)*&(\w+)( \w+)*$" /></p>
<p>
<label>String: </label>
<input id="result" type="text" disabled="disabled" />
</p>
Edit: Alan Moore and nhahtdh pointed out in the comments that this expression can actually be slightly simplified like this:
var reg = /^(\w+[ &])+(\w+( |$))+$/