Martina
Martina

Reputation: 1918

javascript regular expression (end of word)

I think I've a problem with regular expression: I want a string wich can contains all the characthers in the first rounded parenthesis and eventually a [ and finally a ]. the regex is the following:

    var pattern = /^(([a-zA-Z0-9\.\_\-\(\)\\'\xE0\xE8\xE9\xF9\xF2\xEC\x27\,\/]\s?)*\[?([a-zA-Z0-9\.\_\-\(\)\\'\xE0\xE8\xE9\xF9\xF2\xEC\x27\,\/]\s?)*\]?)+$/;

the problem is that if I try to test the following string Maionese [dfvdfv]@ my program will loop forever :-|

the function that I use to test is the following:

//the alert doesn't works
alert(checkSpecialIngredienti("Maionese [dfvdfv]@"));
function checkSpecialIngredienti(s) {

var pattern = /^(([a-zA-Z0-9\.\_\-\(\)\\'\xE0\xE8\xE9\xF9\xF2\xEC\x27\,\/]\s?)*\[?([a-zA-Z0-9\.\_\-\(\)\\'\xE0\xE8\xE9\xF9\xF2\xEC\x27\,\/]\s?)*\]?)+$/;
if (!pattern.test(s)) {
    alert("Attenzione, il campo "+s+"" +
            " che hai inserito non va bene!" +
            "\nIn questo campo puoi inserire " +
            "lettere, numeri, lettere accentate," +
            "punteggiatura classica, singoli spazi e" +
            "\nuna sola coppia di parentesi quadre." +
            "\nRiprova!");
    return (false);
} else
    return true;
}

Upvotes: 2

Views: 762

Answers (1)

Tim Pietzcker
Tim Pietzcker

Reputation: 336078

You're running into catastrophic backtracking because you have nested quantifiers (((...)*)+), and the resulting combinatorial explosion will blow up your regex engine when the subject string cannot be matched.

Now, how to fix this? Let's first simplify your regex. There's a lot of irritating cruft in there - the following regex matches exactly the same strings as yours, but it's easier to read:

/^(([\w\s.,()\\\/'\xE0\xE8\xE9\xF9\xF2\xEC\x27-])*\[?([\w\s.,()\\\/'\xE0\xE8\xE9\xF9\xF2\xEC\x27-])*\]?)+$/

The problem now becomes clear: The []s are both optional, and the @ in your test string is not part of the allowed character range. This means that upon encountering the @, the regex engine needs to backtrack into the match and check if there is any other way to match the preceding part - and there are lots of ways that it has to try.

According to your specs, you don't need the final + at all, since you seem to be wanting to match a string that contains any of the allowed characters plus one optional, [...]-enclosed string of the same characters at the end. In that case, use

/^([\w\s.,()\\\/'\xE0\xE8\xE9\xF9\xF2\xEC\x27-]*)(\[[\w\s.,()\\\/'\xE0\xE8\xE9\xF9\xF2\xEC\x27-]*\])?$/

Upvotes: 2

Related Questions