Three Char Month and Culture matching in javascript - javascript

I have a multi cultural website, where I allow users to enter values in a dd-MMM-yyyy format. I am able to determine the different values based upon their culture in C# (May, English = May, German = Mai)
the problem I am having is the javascript validation of these months. I am able to build the list of acceptable values:
english:
^Jan$|^Feb$|^Mar$|^Apr$|^May$|^Jun$|^Jul$|^Aug$|^Sep$|^Oct$|^Nov$|^Dec$
German:
^Jan$|^Feb$|^Mrz$|^Apr$|^Mai$|^Jun$|^Jul$|^Aug$|^Sep$|^Okt$|^Nov$|^Dez$
I just want to make this regular expression case insensitive. but all the references I see are all pointing me to the /gi flag, but I all of the examples make no sense. I have tried the following and it just doesn't work:
var shouldMatch = "may";
var regexPattern = "^Jan$|^Feb$|^Mar$|^Apr$|^May$|^Jun$|^Jul$|^Aug$|^Sep$|^Oct$|^Nov$|^Dec$/gi"
if(shouldMatch.match(regexPattern) != null) {
//this should happen
}
What am I doing wrong? the regex help out there for javascript is killing me.

jsFiddle Demo
But what about trying to match "mAR" or "MAr", etc.? This quickly becomes an interesting scenario. In my opinion, an easy way to do this is to just match to upper case
var shouldMatch = "May";
var regexPattern = "^JAN$|^FEB$|^MAR$|^APR$|^MAY$|^JUN$|^JUL$|^AUG$|^SEP$|^OCT$|^NOV$|^DEC$";
if(shouldMatch.toUpperCase().match(regexPattern) != null) {
alert("match");
}

regexPattern is a string, not a regular expression.
Convert it to a RegExp before you use it with match:
var regexPattern = new RegExp("^JAN$|^FEB$|^MAR$|^APR$|^MAY$|^JUN$|^JUL$|^AUG$|^SEP$|^OCT$|^NOV$|^DEC$", "gi");
And also, convert the shouldMatch to upper case before you use it:
shouldMatch = shouldMatch.toUpperCase();

Your regular expression should not be a string:
var shouldMatch = "may";
var regexPattern = /^Jan$|^Feb$|^Mar$|^Apr$|^May$|^Jun$|^Jul$|^Aug$|^Sep$|^Oct$|^Nov$|^Dec$/i;
if(shouldMatch.match(regexPattern) != null) {
// this seems happened
}

This should work for you.
Changed to using test
No need for the global "g" flag as you are testing the whole string from beginning "^" to end "$"
Changed string regexPattern into a RegExp object
The "i" flag is needed because you want case insensitive.
Javascript
var shouldMatch = "may";
var regexPattern = /^Jan$|^Feb$|^Mar$|^Apr$|^May$|^Jun$|^Jul$|^Aug$|^Sep$|^Oct$|^Nov$|^Dec$/i;
if(regexPattern.test(shouldMatch)) {
alert(shouldMatch);
}
On jsfiddle
You could also make it a little shorter and a little less ugly by doing this
var regexPattern = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)$/i;
On jsfiddle
As an alternative to regex, you could also use String.indexOf and Array.some, and try each pattern to see if it is in the string you are testing. This example will require a modern browser or a "shim"/"polyfill" for older browsers. You could also check equality "===" if you want to match the whole string rather than see if it is contained in.
Javascript
var shouldMatch = "may";
var patterns = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec".split("|");
var matched = patterns.some(function (pattern) {
if (shouldMatch.toLowerCase().indexOf(pattern.toLowerCase()) !== -1) {
alert(shouldMatch);
return true;
}
return false;
});
On jsfiddle

Or run the possibilities together-
var Rx=/^(jan|feb|m(ar|rz)|apr|ma[iy]|jun|jul|aug|sep|o[ck]t|nov|de[cz])$/i
Rx.test('may');

Related

search a regex and filter it

Hi i am try to find a variable date in a string with a regex and after this i want to save the date in a new variable my code looks like:
var valide =new RegExp(/\d{2}([./-])\d{2}\1\d{4}$/mg);
var text = 'lalaahfdsdfl 02.02.1989';//example
if(valide.test(text) === true){
}
how can i put the found date (02.02.1989) in a new variable
You can create groups in your Regex expression (just put the values you want between parenthesis) and then use this to get the specific group value.
Note, however, I think your regex is wrong... it seems you end with 1 plus 4 digits
You can use match on a string:
var valide =new RegExp(/\d{2}([./-])\d{2}\1\d{4}$/mg);
var text = 'lalaahfdsdfl 02.02.1989';//example
console.dir(text.match(valide)) // ["02.02.1989"]
if(valide.test(text) === true){
}
Using REGEXP function match you can extract the part that match your regular expression.
After this you will get an object. In this case i turn it into a string so you can do a lot more things with it.
var myDate = text.match(valide).toString();
Hope this helps :>
var valide =new RegExp(/\d{2}([./-])\d{2}\1\d{4}$/mg);
var text = 'lalaahfdsdfl 02.02.1989';//example
if(valide.test(text) === true){
var myDate = text.match(valide).toString();
console.log(myDate)
}
You can use match for that:
var valide =new RegExp(/\d{2}([./-])\d{2}\1\d{4}$/mg);
var text = 'lalaahfdsdfl 02.02.1989';//example
var foundDate = text.match(valide);
console.log(foundDate);
Also, you can make the regex a bit simpler if you switch the ([./-]) to ([-.]), because - is considered a literal match if it comes first inside a character class.
You could do something like this.
var result = text.match(valide)
Here is a reference for the match method String.prototype.match

Regex to check whether string starts with, ignoring case differences

I need to check whether a word starts with a particular substring ignoring the case differences. I have been doing this check using the following regex search pattern but that does not help when there is difference in case across the strings.
my case sensitive way:
var searchPattern = new RegExp('^' + query);
if (searchPattern.test(stringToCheck)) {}
Pass the i modifier as second argument:
new RegExp('^' + query, 'i');
Have a look at the documentation for more information.
You don't need a regular expression at all, just compare the strings:
if (stringToCheck.substr(0, query.length).toUpperCase() == query.toUpperCase())
Demo: http://jsfiddle.net/Guffa/AMD7V/
This also handles cases where you would need to escape characters to make the RegExp solution work, for example if query="4*5?" which would always match everything otherwise.
I think all the previous answers are correct. Here is another example similar to SERPRO's, but the difference is that there is no new constructor:
Notice: i ignores the case and ^ means "starts with".
var whateverString = "My test String";
var pattern = /^my/i;
var result = pattern.test(whateverString);
if (result === true) {
console.log(pattern, "pattern matched!");
} else {
console.log(pattern, "pattern did NOT match!");
}
Here is the jsfiddle (old version) if you would like to give it a try.
In this page you can see that modifiers can be added as second parameter. In your case you're are looking for 'i' (Canse insensitive)
//Syntax
var patt=new RegExp(pattern,modifiers);
//or more simply:
var patt=/pattern/modifiers;
For cases like these, JS Regex offers a feature called 'flag'. They offer an extra hand in making up Regular Expressions more efficient and widely applicable.
Here, the flag that could be used is the 'i' flag, which ignores cases (upper and lower), and matches irrespective of them (cases).
Literal Notation:
let string = 'PowerRangers'
let regex = /powerrangers/i
let result = regex.test(string) // true
Using the JS 'RegExp' constructor:
let string = 'PowerRangers'
let regex = new RegExp('powerrangers', 'i')
let result = regex.test(string)
2022, ECMA 11
Just created this helper function, I find it more useful and clean than modifying the regex and recreating one everytime.
/**
* #param {string} str
* #param {RegExp} search
* #returns {boolean}
*/
function regexStartsWith (str, search, {caseSensitive = true} = {})
{
var source = search.source
if (!source.startsWith('^')) source = '^' + source
var flags = search.flags
if (!caseSensitive && !flags.includes('i')) flags += 'i'
var reg = new RegExp(source, flags)
return reg.test(str)
}
Use it this way:
regexStartsWith('can you Fi nD me?', /fi.*nd/, {caseSensitive: false})

Remove non-numeric characters except points, commas and '$'?

I need a function to remove all characters except numbers + characters: '$', '.' and ','.
How can I do this?
> 'worth $12,345.00 dollars'.replace(/[^0-9$.,]/g, '')
"$12,345.00"
This is the answer you asked for. I would not recommend it for extracting currencies, since it can suffer from problems like this:
> 'A set of 12 worth between $123 and $456. A good buy.'.replace(/[^0-9$.,]/g, '')
"12$123$456.."
If you want to just extract expressions of a currency-like form, you could do:
> 'set of 12 worth between $123.00 and $45,678'.match(/\$[0-9,]+(?:\.\d\d)?/g)
["$123.00", "$45,678"]
If you need more complicated matching (e.g. you'd just like to extract the dollar value and ignore the cent value) you could do something like How do you access the matched groups in a JavaScript regular expression? for example:
> var regex = /\$([0-9,]+)(?:\.(\d\d))?/g;
> while (true) {
> var match = regex.exec('set of 12 worth between $123.00 and $45,678');
> if (match === null)
> break;
> console.log(match);
> }
["$123.00", "123", "00"]
["$45,678", "45,678", undefined]
(Thus be careful, javascript regexp objects are not immutable/final objects, but have state and can be used for iteration as demonstrated above. You thus cannot "reuse" a regexp object. Even passing myRegex2 = RegExp(myRegex) will mix state; a very poor language decision for the constructor. See the addendum on how to properly clone regexes in javascript.) You can rewrite the above as a very exotic for-loop if you'd like:
var myString = 'set of 12 worth between $123.00 and $45,678';
var regex = '\$([0-9,]+)(?:\.(\d\d))?';
for(var match, r=RegExp(regex,'g'); match=regex.exec(myString) && match!==null; )
console.log(match);
addendum - Why you can't reuse javascript RegExp objects
Bad language design, demonstrating how state is reused:
var r=/(x.)/g
var r2 = RegExp(r)
r.exec('xa xb xc')
["xa", "xa"]
r2.exec('x1 x2 x3')
["x2", "x2"]
How to properly clone a regex in javascript (you have to define it with a string):
var regexTemplate = '(x.)'
var r = RegExp(regexTemplate, 'g')
var r2 = RegExp(regexTemplate, 'g')
r.exec('xa xb xc')
["xa", "xa"]
r2.exec('x1 x2 x3')
["x1", "x1"]
If you wish to programmatically preserve flags such as 'g', you can probably use regexTemplate = ['(x.)', 'g']; RegExp.apply(this, regexTemplate).
If you do not want to allow someone to type such values in a textbox then jQuery Numeric is a nice plugin that does exactly what you want,

.match() with a regular expression returns null

I am trying to do something I thought would be pretty easy to do, which is to restrict a string to certain characters by matching a regular expression.
var value = 'FailureStr1ng';
var type = 'ALPHA';
var regex = null;
switch(type) {
case 'ALPHA':
regex = '^[a-zA-Z]+$';
break;
case 'NUMERIC':
regex = '^[0-9]+$';
break;
case 'ALPHANUMERIC':
regex = '^[a-zA-Z0-9]+$';
break;
}
return value.match(regex);
For some reason, when using the match it always returns null. Is there a way to fix this, or a better method to do this?
Note: The code here is a snippet of much larger code, and in turn the value and type variable are usually defined by another method.
You want RegExp.test, which tests a value for a match instead of retrieving the match. With your existing code, that would mean:
if(!new RegExp(regex).test(value)){
alert('Your string was invalid.');
}
However, it would be preferable to use RegExp literals instead of strings, as they're much more efficient and clear, and less prone to error:
var value = 'FailureStr1ng';
var type = 'ALPHA';
var regex = null;
switch(type) {
case 'ALPHA':
regex = /^[a-zA-Z]+$/;
break;
case 'NUMERIC':
regex = /^[0-9]+$/;
break;
case 'ALPHANUMERIC':
regex = /^[a-zA-Z0-9]+$/;
break;
}
if(!regex.test(value)) {
alert('Your string was invalid.');
}
Even better, use a dictionary:
var expressions = {
ALPHA: /^[a-zA-Z]+$/,
NUMERIC: /^[0-9]+$/,
ALPHANUMERIC: /^[a-zA-Z0-9]+$/
};
if(!expressions[type].test(value)) {
alert('Your string was invalid.');
}
Regex must be surrounded with /, not ', so that JavaScript creates a variable of type regex, not of type string. So for instance, for your ALPHA case, you should have
regex = /^[a-zA-Z]+$/;
See MDN's page on .match for more information about using .match.
Your code looks like it's inside a function { ... }. Are you returning anything? If not, that's why you're getting null back...
Also, regexes are surrounded by slashes (/.../), not quotes.

How can I concatenate regex literals in JavaScript?

Is it possible to do something like this?
var pattern = /some regex segment/ + /* comment here */
/another segment/;
Or do I have to use new RegExp() syntax and concatenate a string? I'd prefer to use the literal as the code is both more self-evident and concise.
Here is how to create a regular expression without using the regular expression literal syntax. This lets you do arbitary string manipulation before it becomes a regular expression object:
var segment_part = "some bit of the regexp";
var pattern = new RegExp("some regex segment" + /*comment here */
segment_part + /* that was defined just now */
"another segment");
If you have two regular expression literals, you can in fact concatenate them using this technique:
var regex1 = /foo/g;
var regex2 = /bar/y;
var flags = (regex1.flags + regex2.flags).split("").sort().join("").replace(/(.)(?=.*\1)/g, "");
var regex3 = new RegExp(expression_one.source + expression_two.source, flags);
// regex3 is now /foobar/gy
It's just more wordy than just having expression one and two being literal strings instead of literal regular expressions.
Just randomly concatenating regular expressions objects can have some adverse side effects. Use the RegExp.source instead:
var r1 = /abc/g;
var r2 = /def/;
var r3 = new RegExp(r1.source + r2.source,
(r1.global ? 'g' : '')
+ (r1.ignoreCase ? 'i' : '') +
(r1.multiline ? 'm' : ''));
console.log(r3);
var m = 'test that abcdef and abcdef has a match?'.match(r3);
console.log(m);
// m should contain 2 matches
This will also give you the ability to retain the regular expression flags from a previous RegExp using the standard RegExp flags.
jsFiddle
I don't quite agree with the "eval" option.
var xxx = /abcd/;
var yyy = /efgh/;
var zzz = new RegExp(eval(xxx)+eval(yyy));
will give "//abcd//efgh//" which is not the intended result.
Using source like
var zzz = new RegExp(xxx.source+yyy.source);
will give "/abcdefgh/" and that is correct.
Logicaly there is no need to EVALUATE, you know your EXPRESSION. You just need its SOURCE or how it is written not necessarely its value. As for the flags, you just need to use the optional argument of RegExp.
In my situation, I do run in the issue of ^ and $ being used in several expression I am trying to concatenate together! Those expressions are grammar filters used accross the program. Now I wan't to use some of them together to handle the case of PREPOSITIONS.
I may have to "slice" the sources to remove the starting and ending ^( and/or )$ :)
Cheers, Alex.
Problem If the regexp contains back-matching groups like \1.
var r = /(a|b)\1/ // Matches aa, bb but nothing else.
var p = /(c|d)\1/ // Matches cc, dd but nothing else.
Then just contatenating the sources will not work. Indeed, the combination of the two is:
var rp = /(a|b)\1(c|d)\1/
rp.test("aadd") // Returns false
The solution:
First we count the number of matching groups in the first regex, Then for each back-matching token in the second, we increment it by the number of matching groups.
function concatenate(r1, r2) {
var count = function(r, str) {
return str.match(r).length;
}
var numberGroups = /([^\\]|^)(?=\((?!\?:))/g; // Home-made regexp to count groups.
var offset = count(numberGroups, r1.source);
var escapedMatch = /[\\](?:(\d+)|.)/g; // Home-made regexp for escaped literals, greedy on numbers.
var r2newSource = r2.source.replace(escapedMatch, function(match, number) { return number?"\\"+(number-0+offset):match; });
return new RegExp(r1.source+r2newSource,
(r1.global ? 'g' : '')
+ (r1.ignoreCase ? 'i' : '')
+ (r1.multiline ? 'm' : ''));
}
Test:
var rp = concatenate(r, p) // returns /(a|b)\1(c|d)\2/
rp.test("aadd") // Returns true
Providing that:
you know what you do in your regexp;
you have many regex pieces to form a pattern and they will use same flag;
you find it more readable to separate your small pattern chunks into an array;
you also want to be able to comment each part for next dev or yourself later;
you prefer to visually simplify your regex like /this/g rather than new RegExp('this', 'g');
it's ok for you to assemble the regex in an extra step rather than having it in one piece from the start;
Then you may like to write this way:
var regexParts =
[
/\b(\d+|null)\b/,// Some comments.
/\b(true|false)\b/,
/\b(new|getElementsBy(?:Tag|Class|)Name|arguments|getElementById|if|else|do|null|return|case|default|function|typeof|undefined|instanceof|this|document|window|while|for|switch|in|break|continue|length|var|(?:clear|set)(?:Timeout|Interval))(?=\W)/,
/(\$|jQuery)/,
/many more patterns/
],
regexString = regexParts.map(function(x){return x.source}).join('|'),
regexPattern = new RegExp(regexString, 'g');
you can then do something like:
string.replace(regexPattern, function()
{
var m = arguments,
Class = '';
switch(true)
{
// Numbers and 'null'.
case (Boolean)(m[1]):
m = m[1];
Class = 'number';
break;
// True or False.
case (Boolean)(m[2]):
m = m[2];
Class = 'bool';
break;
// True or False.
case (Boolean)(m[3]):
m = m[3];
Class = 'keyword';
break;
// $ or 'jQuery'.
case (Boolean)(m[4]):
m = m[4];
Class = 'dollar';
break;
// More cases...
}
return '<span class="' + Class + '">' + m + '</span>';
})
In my particular case (a code-mirror-like editor), it is much easier to perform one big regex, rather than a lot of replaces like following as each time I replace with a html tag to wrap an expression, the next pattern will be harder to target without affecting the html tag itself (and without the good lookbehind that is unfortunately not supported in javascript):
.replace(/(\b\d+|null\b)/g, '<span class="number">$1</span>')
.replace(/(\btrue|false\b)/g, '<span class="bool">$1</span>')
.replace(/\b(new|getElementsBy(?:Tag|Class|)Name|arguments|getElementById|if|else|do|null|return|case|default|function|typeof|undefined|instanceof|this|document|window|while|for|switch|in|break|continue|var|(?:clear|set)(?:Timeout|Interval))(?=\W)/g, '<span class="keyword">$1</span>')
.replace(/\$/g, '<span class="dollar">$</span>')
.replace(/([\[\](){}.:;,+\-?=])/g, '<span class="ponctuation">$1</span>')
It would be preferable to use the literal syntax as often as possible. It's shorter, more legible, and you do not need escape quotes or double-escape backlashes. From "Javascript Patterns", Stoyan Stefanov 2010.
But using New may be the only way to concatenate.
I would avoid eval. Its not safe.
You could do something like:
function concatRegex(...segments) {
return new RegExp(segments.join(''));
}
The segments would be strings (rather than regex literals) passed in as separate arguments.
You can concat regex source from both the literal and RegExp class:
var xxx = new RegExp(/abcd/);
var zzz = new RegExp(xxx.source + /efgh/.source);
Use the constructor with 2 params and avoid the problem with trailing '/':
var re_final = new RegExp("\\" + ".", "g"); // constructor can have 2 params!
console.log("...finally".replace(re_final, "!") + "\n" + re_final +
" works as expected..."); // !!!finally works as expected
// meanwhile
re_final = new RegExp("\\" + "." + "g"); // appends final '/'
console.log("... finally".replace(re_final, "!")); // ...finally
console.log(re_final, "does not work!"); // does not work
No, the literal way is not supported. You'll have to use RegExp.
the easier way to me would be concatenate the sources, ex.:
a = /\d+/
b = /\w+/
c = new RegExp(a.source + b.source)
the c value will result in:
/\d+\w+/
I prefer to use eval('your expression') because it does not add the /on each end/ that ='new RegExp' does.

Categories