The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 4,224 other subscribers

JavaScript. Sigh. No real RegExp support. Sigh. Google Search results. Sigh.

Posted by jpluimers on 2017/03/01

Prologue

Every time I need to use JavaScript there’s this tiny voice in the back of my head “Please don’t”, for instance because of

JavaScript has two sets of equality operators: === and !==, and their evil twins == and !=.

Verify a URI in JavaScript with a Regular Expression using Google Search examples

This time it did it again: I used JavaScript. My need was to verify a basic URI in JavaScript, so I wrote this function based on RFC 3986 [WayBack] which in Appendix B has a nice regular expression: ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?

function isValidUri(uri){
    var uriRegExPattern = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?";
    var uriRegEx = new RegExp(uriRegExPattern); 

    return (uriRegEx.test(uri));
} 

It would crash. But JavaScript is JavaScript, so even a site like JSFiddle wouldn’t show an error (later I found out that enabling the console on http://jsbin.com/wamavacuco/edit?html,console,output does show the error in the console complete with stack trace).

So I would write an exception handler around them like dozens of exception handling examples performing an alert using a description property or message property.

  try {
    // function body
  } 

  catch (e) {
    alert("isValidUri Error: " + e.description);
    return false;
  }

Finally I got the exceptions right and wrote this exception handler around it:

  try {
    // function body
  } 

  catch (e) {
    alert("isValidUri Error: " + e);
    return false;
  }

Now I finally got a decent error message:

isValidUri error: SyntaxError: Invalid regular expression: /^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(?([^#]*))?(#(.*))?/: Invalid group

Conclusion

I learned two lessons here:

  1. When you write in a new programming language, don’t trust the Google Search results. The worst recommendations get the best hits, in this case for the exception handling in JavaScript.
  2. Do not trust all regular expressions to be supported in any environment. There are too many regex flavours. No environment supports them all.

Epilogue

This was the jsbin stack trace:

"error"
"SyntaxError: Invalid regular expression: /^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(?([^#]*))?(#(.*))?/: Invalid group
    at RegExp (native)
    at isValidUri (:6:26)
    at HTMLButtonElement.onclick (http://null.jsbin.com/runner:1:968)"

The RegEx101 Python interpreter understands the regex and supports seamless switch to JavaScript support or PCRE support. I hoped this would enabled me to fiddle around long enough. But it didn’t show the error. Apparently it doesn’t fully do what JavaScript does.

The cause was (after a long search) answered in Invalid Group with Regex Expression in Javascript – Stack Overflow – thanks melpomene: either escape backslashes or use slash surrounded regex literals.

/1?[\s-]?\(?(\d{3})\)?[\s-]?(\d{3})[\s-]?(\d{4})/ works fine in JavaScript.

However, my crystal ball says you’re using a string that you’re passing to the RegExp constructor:

new RegExp("1?[\s-]?\(?(\d{3})\)?[\s-]?(\d{3})[\s-]?(\d{4})")

This is wrong because backslashes have a special meaning in strings, so

"1?[\s-]?\(?(\d{3})\)?[\s-]?(\d{3})[\s-]?(\d{4})"

is equivalent to

"1?[s-]?(?(d{3}))?[s-]?(d{3})[s-]?(d{4})"

(because "\(" is "("). That would complain about an invalid group at (?(.

Solution: Either use a regex literal (/.../) or double your backslashes in the string.

–jeroen

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

 
%d bloggers like this: