Avatar of wwarby
wwarby

asked on 

Strange JavaScript Regex Behavior in Firefox and Opera After KeyUp Event

Create a page containing the attached code snippet and view the page in Firefox (or Opera, they both do this, but not IE or Safari). Type "8" (or any other digit) followed by a single letter, say "e", repeated several times. Each time you hit the "e" key, the result of the RegExp test that gets printed back into the second text box will alternate between true/false. WHY???

This simplified test case demonstrates what I think is a bug, but one that appears in current versions of two major browsers. The regular expression is testing for the existence of a digit. If I put one digit at the start of the test string, no quantity of subsequent characters should alter the result. This is one example of many - I have found that many regex patterns return unexpected results when used to test the value of a text box following the KEYUP event.

If you place a breakpoint on the return line and copy the return expression into the Firebug console it will always return true, even though executing that same line immediately after returns false.

The answer I am looking for is either an explanation of this behaviour that would convince me it isn't a bug, or a practical workaround that makes the second box always return true. Meanwhile I've reported it on BugZilla.
<html>
	<body>
		<input type="text" id="foo" onkeyup="javascript:document.getElementById('bar').value = hasDigits(this.value);" />
		<input type="text" id="bar" />
		<script type="text/javascript">
			function hasDigits(p) {
				return /\d/g.test(p);
			}
		</script>
	</body>
</html>

Open in new window

Web BrowsersRegular ExpressionsJavaScript

Avatar of undefined
Last Comment
wwarby
Avatar of abel
abel
Flag of Netherlands image

Hmm. Intriguing. The regex should test the value in the textbox, it seems as if that value is not always equal to what you actually see?

Btw, you don't need a letter to have this behavior. Hit Shift, Alt, Ctrl (without anything else), or Home, End, arrow keys, whatever you fancy: the behavior is the same regardless.

On thing that can be said of this "bug" (if it is one, but I'll get back at you) is that it is very consistent... :)
ASKER CERTIFIED SOLUTION
Avatar of abel
abel
Flag of Netherlands image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
Avatar of abel
abel
Flag of Netherlands image

One more thing on this quest. Though it is not a bug, it seems odd that just typing nothing (i.e., Ctrl, Alt, Home etc) also triggers this behavior. But if you think of it, in the light of my analysis above, you'll see that it is consistent: the lastIndex property is moved one position to the right, which is, when a string is made of one character, the end of the string. Then, /\d/ will match false. Next time, the pointer is at the beginning of the string. Then, /\d/ will match true.

Like I said: intriguing. Like I said: not intuitive :)
Avatar of wwarby
wwarby

ASKER

Ah. You know what, I've hit this same problem before in a different disguise and I didn't recognise it. Unfortunately is that the example I've given is hugely simplified from what I'm actually trying to achieve. Suffice to say anyway that in this instance I can live without the "g" modifier and that has corrected the behaviour. That said, there will be instances where I can't do without it. In those cases, would the "new RegExp()" constructor syntax be the way to go?

Kudos on the quick and thorough response ;)

-William
Avatar of abel
abel
Flag of Netherlands image

> In those cases, would the "new RegExp()" constructor syntax be the way to go?

That is the safest, I believe. There are subtle differences between the following four versions (one will throw an error, I don't consider that one):

  1. Will call the constructor of RegExp, because the first argument is of type String and the second is not undefined
  2. Will not call the constructor of RegExp, instead, it returns the first argument
  3. Will call the constructor because of "new"
  4. Will call the constructor because of "new" and create a regular expresion object that is a copy of the the first argument and resets lastIndex.
When I say "will call the constructor" it means that a fresh new object will be created and the lastIndex property will be reset.

If you use the syntax as you described, the same happens as number 2 below, without the lastIndex property being reset. You can, however, reset that property manually as follows, which will also cure this problem (then, you will have to assign your /\d/g firstly, of course):

re.lastIndex = 0;

Hope this helps, and thanks for the points :)

Cheers,
Abel

PS: oh, and this all is per the behavior of the ECMA-262 specification. It is described in section 15.10: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf.
1.  var re = RegExp("\\d", "g");
2.  var re = RegExp(/\d/g);
2a. var re = RegExp(/\d/, "g");  // error
3.  var re = new RegExp("\\d", "g");
4.  var re = new RegExp(/\d/g);

Open in new window

Avatar of wwarby
wwarby

ASKER

Thanks for the detailed additional explanation - saves me a lot of headaches looking all this stuff up ;)
JavaScript
JavaScript

JavaScript is a dynamic, object-based language commonly used for client-side scripting in web browsers. Recently, server side JavaScript frameworks have also emerged. JavaScript runs on nearly every operating system and in almost every mainstream web browser.

127K
Questions
--
Followers
--
Top Experts
Get a personalized solution from industry experts
Ask the experts
Read over 600 more reviews

TRUSTED BY

IBM logoIntel logoMicrosoft logoUbisoft logoSAP logo
Qualcomm logoCitrix Systems logoWorkday logoErnst & Young logo
High performer badgeUsers love us badge
LinkedIn logoFacebook logoX logoInstagram logoTikTok logoYouTube logo