How to invert an existing regular expression in javascript? - javascript

I have created a regex to validate time as follows : ([01]?\d|2[0-3]):[0-5]\d.
Matches TRUE : 08:00, 09:00, 9:00, 13:00, 23:59.
Matches FALSE : 10.00, 24:00, 25:30, 23:62, afdasdasd, ten.
QUESTION
How to invert a javascript regular expression to validate if NOT time?
NOTE - I have seen several ways to do this on stack but cannot seem to make them work for my expression because I do not understand how the invert expression should work.
http://regexr.com?38ai1
ANSWER
Simplest solution was to invert the javascript statement and NOT the regex itself.
if (!(/^(([01]?\d|2[0-3]):[0-5]\d)/.test(obj.value))
Simply adding ! to create an if NOT statement.

A regular expression is usually used for capturing some specific condition(s) - the more specific, the better the regex. What you're looking for is an extremely broad condition to match because just about everything wouldn't be considered "time" (a whitespace, a special character, an alphabet character, etc etc etc).
As suggested in the comments, for what you're trying to achieve, it makes much more sense to look for a time and then check (and negate) the result of that regular expression.

As i mentioned in the comment, the better way is to negate the test rather then create a new regexp that matches any non-time.
However, if you really need the regexp, you could use negative lookahead to match the start of something that is not a time:
/^(?!([01]?\d|2[0-3]):[0-5]\d$)/
DEMO: http://regex101.com/r/bD3aG4
Note that i anchored the regexp (^ and $), which might not work with what you need it for.

Related

Is regex a costly operation? It seems atleast

I was writing a regex pattern for a string. The string being a constant type/structure. What I mean is, it looks like(this format is not so important, have a look at the example next)-
[Data Code Format]: POP N/N/N (N: object): JSON object data
Here N represents a number or digit. and what's inside [ ] is a set of string block. But, this format is constant.
So, I wrote a regex-
\s*((?:\S+\s+){1}\S+)\s*(?:\((?:.*?)\))?:\s*(\S*)\s*(\w+)
Keeping this string example in mind-
%DATA-4-JSON: POP 0/1/0 (1: object): JSON object data
It works perfectly, but, what I see on regex101.com is that there is a successful match. But, it has undergone 330 steps to achieve this.
Screenshot-
My question is, its taking 330 steps to achieve this(atleast in my mind I feel its pretty heavy), which I guess can be achieved using if-else and other comparisons with lesser steps right?
I mean, is regex string parsing so heavy? 330 steps for like 10000's of strings I need to parse is going to be heavy right?
When you are using regexps, they can be costly if you use backtracking. When you use quantifiers with consequent patterns that may match one another (and in case the patterns between them may match empty strings (usually, declared with *, {0,x} or ? quantifiers)), backtracking might play a bad trick on you.
What is bad about your regex?
A slight performance issue is caused by an unnecessary non-capturing group (?:\S+\s+){1}. It can be written as \S+\s+ and it will already decrease the number of steps (a bit, 302 steps). However, the worst part is that \S matches the : delimiter. Thus, the regex engine has to try a lot of possible routes to match the beginning of your expected match. Replace that \S+\s+\S with [^:\s]+\s+[^:\s]+, and the step amount will decrease to 159!
Now, coming to (?:\((?:.*?)\))? - removing the unnecessary inner non-capturing group gives another slight improvement (148 steps), and replacing .*? with a negated character class gives another boost (139 steps).
I'd use this for now:
\s*([^:\s]+\s+[^:\s]+)\s*(?:\([^()]*\))?:\s*(\S*)\s*(\w+)
If the initial \s* was obligatory, it would be another enhancement, but you would have different matches.

What is wrong with these regexes with backreferences?

I am trying to make a regex that will match a number of x's that is a power of two. I am using JavaScript. I tried this one:
^(x\1?)$
but it doesn't work. Shouldn't the \1 refer to the outer parathesis so it should match xx, and therefore also xxxx, etc.?
I tried a simpler one that I thought would match x and xx:
^((x)|(\2{2}))$
but this only matches x.
What am I doing wrong?
You can't do "recursive backreferences". At least, it is not so easy.
I'm no sure that you need recuresive regular expressions here. May be you could just count number of the characters in the string and check if it is equal to a power of two?
But if you really need recursive regular expressions (I'm almost sure, you don't),
you can check this question:
Recursive matching with regular expressions in Javascript
and this blog
http://blog.stevenlevithan.com/archives/javascript-match-nested

Solving regular expression recursive strings

The Problem
I could match this string
(xx)
using this regex
\([^()]*\)
But it wouldn't match
(x(xx)x)
So, this regex would
\([^()]*\([^()]*\)[^()]*\)
However, this would fail to match
(x(x(xx)x)x)
But again, this new regex would
[^()]*\([^()]*\([^()]*\)[^()]*\)[^()]*
This is where you can notice the replication, the entire regex pattern of the second regex after the first \( and before the last \) is copied and replaces the center most [^()]*. Of course, this last regex wouldn't match
(x(x(x(xx)x)x)x)
But, you could always copy replace the center most [^()]* with [^()]*\([^()]*\)[^()]* like we did for the last regex and it'll capture more (xx) groups. The more you add to the regex the more it can handle, but it will always be limited to how much you add.
So, how do you get around this limitation and capture a group of parenthesis (or any two characters for that matter) that can contain extra groups within it?
Falsely Assumed Solutions
I know you might think to just use
\(.*\)
But this will match all of
(xx)xx)
when it should only match the sub-string (xx).
Even this
\([^)]*\)
will not match pairs of parentheses that have pairs nested like
(xx(xx)xx)
From this, it'll only match up to (xx(xx).
Is it possible?
So is it possible to write a regex that can match groups of parentheses? Or is this something that must be handled by a routine?
Edit
The solution must work in the JavaScript implementation of Regular Expressions
If you want to match only if the round brackets are balanced you cannot do it by regex itself..
a better way would be to
1>match the string using \(.*\)
2>count the number of (,) and check if they are equal..if they are then you have the match
3>if they are not equal use \([^()]*\) to match the required string
Formally speaking, this isn't possible using regular expressions! Regular expressions define regular languages, and regular languages can't have balanced parenthesis.
However, it turns out that this is the sort of thing people need to do all the time, so lots of Regex engines have been extended to include more than formal regular expressions. Therefore, you can do balanced brackets with regular expressions in javascript. This article might help get you started: http://weblogs.asp.net/whaggard/archive/2005/02/20/377025.aspx . It's for .net, but the same applies for the standard javascript regex engine.
Personally though, I think it's best to solve a complex problem like this with your own function rather than leveraging the extended features of a Regex engine.

Regular expression: Get the matched value of each match in a Kleene-star expression?

In particular, is this possible with Javascript?
>> "Version 1.2.3.4".match(/\S+ (\d+)(\.\d+)*/)
["Version 1.2.3.4", "1", ".4"]
It's obvious $2 gets set to the last Kleene-"match". Is there no built-in method to retrieve the rest (".2", ".3")?
If this cannot be done easily in JS, could Perl do it?
UPDATE: Many of the answers so far have been "workarounds" which work because of the simplicity of my example. If the part that repeated that I wanted to match was more than just a number, they wouldn't work.
However, a very valid solution does exist: use /expr/g global regex matching: just filter out the parts that repeat and use that. I find this to be somewhat less flexible than the more generally applicable * operator but it will obviously get the job done in most cases.
Regex in JavaScript, like most other regex flavors, only captures the last value of the capturing group if it is matched repeatedly. The only well known regex lib (that I know of) where you get access to all of the previous matched captures is the one in .NET.
So no, you can't do this in JS.
In Perl there are a couple of ways you can accomplish such things. One of the more elegant is probably to use \G (which works in PCRE too).
For example:
"Version 1.2.3.4" =~ /(?:\S+ |\G(?!^)\.)(\d+)/g
Returns (in list context):
(1, 2, 3, 4)
Why not match the whole version string, then split by .?
>> "Version 1.2.3.4".match(/\S+ (\d+(?:\.\d+)*)/)[1].split('.')
Just capture the whole version number string and then split on the period character.
Regex for matching the whole number: /((?:\d+)(?:\.\d+)*)/
Then simply call split on the resulting capture.
Regex \.?\d+ will return you what you need, but you have to run this regex for all matches, not just one...
var n=str.match(/\.?\d+/g);
If you want to match just numbers without leading dot, then go with regex \d+.
var n=str.match(/\d+/g);

Match altered version of first match with only one expression?

I'm writing a brush for Alex Gorbatchev's Syntax Highlighter to get highlighting for Smalltalk code. Now, consider the following Smalltalk code:
aCollection do: [ :each | each shout ]
I want to find the block argument ":each" and then match "each" every time it occurrs afterwards (for simplicity, let's say every occurrence an not just inside the brackets).
Note that the argument can have any name, e.g. ":myArg".
My attempt to match ":each":
\:([\d\w]+)
This seems to work. The problem is for me to match the occurrences of "each". I thought something like this could work:
\:([\d\w]+)|\1
But the right hand side of the alternation seems to be treated as an independent expression, so backreferencing doesn't work.
Is it even possible to accomplish what I want in a single expression? Or would I have to use the backreference within a second expression (via another function call)?
You could do it in languages that support variable-length lookbehind (AFAIK only the .NET framework languages do, Perl 6 might). There you could highlight a word if it matches (?<=:(\w+)\b.*)\1. But JavaScript doesn't support lookbehind at all.
But anyway this regex would be very inefficient (I just checked a simple example in RegexBuddy, and the regex engine needs over 60 steps for nearly every character in the document to decide between match and non-match), so this is not a good idea if you want to use it for code highlighting.
I'd recommend you use the two-step approach you mentioned: First match :(\w+)\b (word boundary inserted for safety, \d is implied in \w), then do a literal search for match result \1.
I believe the only thing stored by the Regex engine between matches is the position of the last match. Therefore, when looking for the next match, you cannot use a backreference to the match before.
So, no, I do not think that this is possible.

Categories

Resources