Regex Wildcard for Array Search - javascript

I have a json array that I currently search through by flipping a boolean flag:
for (var c=0; c<json.archives.length; c++) {
if ((json.archives[c].archive_num.toLowerCase().indexOf(query)>-1)){
inSearch = true;
} }
And I have been trying to create a wildcard regex search by using a special character '*' but I haven't been able to loop through the array with my wildcard.
So what I'm trying to accomplish is when query = '199*', replace the '*' with /[\w]/ and essentially search for 1990,1991,1992,1993,1994 + ... + 199a,199b, etc.
All my attempts turn literal and I end up searching '199/[\w]/'.
Any ideas on how to create a regex wildcard to search an array?
Thanks!

You should write something like this:
var query = '199*';
var queryPattern = query.replace(/\*/g, '\\w');
var queryRegex = new RegExp(queryPattern, 'i');
Next, to check each word:
if(json.archives[c].archive_num.match(queryRegex))
Notes:
Consider using ? instead of *, * usually stands for many letters, not one.
Note that we have to escape the backslash so it will create a valid string literal. The string '\w' is the same as the string w - the escape is ignored in this case.
You don't need delimiters (/.../) when creating a RegExp object from a string.
[\w] is the same as \w. Yeah, minor one.
You can avoid partial matching by using the pattern:
var queryPattern = '\\b' query.replace(/\*/g, '\\w') + '\\b';
Or, similarly:
var queryPattern = '^' query.replace(/\*/g, '\\w') + '$';

var qre = query.replace(/[^\w\s]/g, "\\$&") // escape special chars so they dont mess up the regex
.replace("\\*", "\\w"); // replace the now escaped * with '\w'
qre = new RegExp(qre, "i"); // create a regex object from the built string
if(json.archives[c].archive_num.match(qre)){
//...
}

Related

Need to replace a string from a long string in javascript

I have a long string
Full_str1 = 'ab#xyz.com;cab#xyz.com;c-ab#xyz.com;c.ab#xyz.com;c_ab#xyz.com;';
removable_str2 = 'ab#xyz.com;';
I need to have a replaced string which will have
resultant Final string should look like,
cab#xyz.com;c-ab#xyz.com;c.ab#xyz.com;c_ab#xyz.com;
I tried with
str3 = Full_str1.replace(new RegExp('(^|\\b)' +removable_str2, 'g'),"");
but it resulted in
cab#xyz.com;c-c.c_ab#xyz.com;
Here a soluce using two separated regex for each case :
the str to remove is at the start of the string
the str to remove is inside or at the end of the string
PS :
I couldn't perform it in one regex, because it would remove an extra ; in case of matching the string to remove inside of the global string.
const originalStr = 'ab#xyz.com;cab#xyz.com;c-ab#xyz.com;c.ab#xyz.com;ab#xyz.com;c_ab#xyz.com;';
const toRemove = 'ab#xyz.com;';
const epuredStr = originalStr
.replace(new RegExp(`^${toRemove}`, 'g'), '')
.replace(new RegExp(`;${toRemove}`, 'g'), ';');
console.log(epuredStr);
First, the dynamic part must be escaped, else, . will match any char but a line break char, and will match ab#xyz§com;, too.
Next, you need to match this only at the start of the string or after ;. So, you may use
var Full_str1 = 'ab#xyz.com;cab#xyz.com;c-ab#xyz.com;c.ab#xyz.com;c_ab#xyz.com;';
var removable_str2 = 'ab#xyz.com;';
var rx = new RegExp("(^|;)" + removable_str2.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), "g");
console.log(Full_str1.replace(rx, "$1"));
// => cab#xyz.com;c-ab#xyz.com;c.ab#xyz.com;c_ab#xyz.com;
Replace "g" with "gi" for case insensitive matching.
See the regex demo. Note that (^|;) matches and captures into Group 1 start of string location (empty string) or ; and $1 in the replacement pattern restores this char in the result.
NOTE: If the pattern is known beforehand and you only want to handle ab#xyz.com; pattern, use a regex literal without escaping, Full_str1.replace(/(^|;)ab#xyz\.com;/g, "$1").
i don't find any particular description why you haven't tried like this it will give you desired result cab#xyz.com;c-ab#xyz.com;c.ab#xyz.com;c_ab#xyz.com;
const full_str1 = 'ab#xyz.com;cab#xyz.com;c-ab#xyz.com;c.ab#xyz.com;c_ab#xyz.com;';
const removable_str2 = 'ab#xyz.com;';
const result= full_str1.replace(removable_str2 , "");
console.log(result);

Use dynamic (variable) string as regex pattern in JavaScript

I want to add a (variable) tag to values with regex, the pattern works fine with PHP but I have troubles implementing it into JavaScript.
The pattern is (value is the variable):
/(?!(?:[^<]+>|[^>]+<\/a>))\b(value)\b/is
I escaped the backslashes:
var str = $("#div").html();
var regex = "/(?!(?:[^<]+>|[^>]+<\\/a>))\\b(" + value + ")\\b/is";
$("#div").html(str.replace(regex, "" + value + ""));
But this seem not to be right, I logged the pattern and its exactly what it should be.
Any ideas?
To create the regex from a string, you have to use JavaScript's RegExp object.
If you also want to match/replace more than one time, then you must add the g (global match) flag. Here's an example:
var stringToGoIntoTheRegex = "abc";
var regex = new RegExp("#" + stringToGoIntoTheRegex + "#", "g");
// at this point, the line above is the same as: var regex = /#abc#/g;
var input = "Hello this is #abc# some #abc# stuff.";
var output = input.replace(regex, "!!");
alert(output); // Hello this is !! some !! stuff.
JSFiddle demo here.
In the general case, escape the string before using as regex:
Not every string is a valid regex, though: there are some speciall characters, like ( or [. To work around this issue, simply escape the string before turning it into a regex. A utility function for that goes in the sample below:
function escapeRegExp(stringToGoIntoTheRegex) {
return stringToGoIntoTheRegex.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
var stringToGoIntoTheRegex = escapeRegExp("abc"); // this is the only change from above
var regex = new RegExp("#" + stringToGoIntoTheRegex + "#", "g");
// at this point, the line above is the same as: var regex = /#abc#/g;
var input = "Hello this is #abc# some #abc# stuff.";
var output = input.replace(regex, "!!");
alert(output); // Hello this is !! some !! stuff.
JSFiddle demo here.
Note: the regex in the question uses the s modifier, which didn't exist at the time of the question, but does exist -- a s (dotall) flag/modifier in JavaScript -- today.
If you are trying to use a variable value in the expression, you must use the RegExp "constructor".
var regex = "(?!(?:[^<]+>|[^>]+<\/a>))\b(" + value + ")\b";
new RegExp(regex, "is")
I found I had to double slash the \b to get it working. For example to remove "1x" words from a string using a variable, I needed to use:
str = "1x";
var regex = new RegExp("\\b"+str+"\\b","g"); // same as inv.replace(/\b1x\b/g, "")
inv=inv.replace(regex, "");
You don't need the " to define a regular expression so just:
var regex = /(?!(?:[^<]+>|[^>]+<\/a>))\b(value)\b/is; // this is valid syntax
If value is a variable and you want a dynamic regular expression then you can't use this notation; use the alternative notation.
String.replace also accepts strings as input, so you can do "fox".replace("fox", "bear");
Alternative:
var regex = new RegExp("/(?!(?:[^<]+>|[^>]+<\/a>))\b(value)\b/", "is");
var regex = new RegExp("/(?!(?:[^<]+>|[^>]+<\/a>))\b(" + value + ")\b/", "is");
var regex = new RegExp("/(?!(?:[^<]+>|[^>]+<\/a>))\b(.*?)\b/", "is");
Keep in mind that if value contains regular expressions characters like (, [ and ? you will need to escape them.
I found this thread useful - so I thought I would add the answer to my own problem.
I wanted to edit a database configuration file (datastax cassandra) from a node application in javascript and for one of the settings in the file I needed to match on a string and then replace the line following it.
This was my solution.
dse_cassandra_yaml='/etc/dse/cassandra/cassandra.yaml'
// a) find the searchString and grab all text on the following line to it
// b) replace all next line text with a newString supplied to function
// note - leaves searchString text untouched
function replaceStringNextLine(file, searchString, newString) {
fs.readFile(file, 'utf-8', function(err, data){
if (err) throw err;
// need to use double escape '\\' when putting regex in strings !
var re = "\\s+(\\-\\s(.*)?)(?:\\s|$)";
var myRegExp = new RegExp(searchString + re, "g");
var match = myRegExp.exec(data);
var replaceThis = match[1];
var writeString = data.replace(replaceThis, newString);
fs.writeFile(file, writeString, 'utf-8', function (err) {
if (err) throw err;
console.log(file + ' updated');
});
});
}
searchString = "data_file_directories:"
newString = "- /mnt/cassandra/data"
replaceStringNextLine(dse_cassandra_yaml, searchString, newString );
After running, it will change the existing data directory setting to the new one:
config file before:
data_file_directories:
- /var/lib/cassandra/data
config file after:
data_file_directories:
- /mnt/cassandra/data
Much easier way: use template literals.
var variable = 'foo'
var expression = `.*${variable}.*`
var re = new RegExp(expression, 'g')
re.test('fdjklsffoodjkslfd') // true
re.test('fdjklsfdjkslfd') // false
Using string variable(s) content as part of a more complex composed regex expression (es6|ts)
This example will replace all urls using my-domain.com to my-other-domain (both are variables).
You can do dynamic regexs by combining string values and other regex expressions within a raw string template. Using String.raw will prevent javascript from escaping any character within your string values.
// Strings with some data
const domainStr = 'my-domain.com'
const newDomain = 'my-other-domain.com'
// Make sure your string is regex friendly
// This will replace dots for '\'.
const regexUrl = /\./gm;
const substr = `\\\.`;
const domain = domainStr.replace(regexUrl, substr);
// domain is a regex friendly string: 'my-domain\.com'
console.log('Regex expresion for domain', domain)
// HERE!!! You can 'assemble a complex regex using string pieces.
const re = new RegExp( String.raw `([\'|\"]https:\/\/)(${domain})(\S+[\'|\"])`, 'gm');
// now I'll use the regex expression groups to replace the domain
const domainSubst = `$1${newDomain}$3`;
// const page contains all the html text
const result = page.replace(re, domainSubst);
note: Don't forget to use regex101.com to create, test and export REGEX code.
var string = "Hi welcome to stack overflow"
var toSearch = "stack"
//case insensitive search
var result = string.search(new RegExp(toSearch, "i")) > 0 ? 'Matched' : 'notMatched'
https://jsfiddle.net/9f0mb6Lz/
Hope this helps

Extending a regex

I'm trying to match javascript files inside /static/js that include ?v=xxxx at the end, 'x' being a character or a number, so it has to match:
http://127.0.0.1:8888/static/js/components/backbone.js?v=a6tsb
But not:
http://127.0.0.1:8888/static/js/views/ribbon.js
http://127.0.0.1:8888/templates/require-config.js
This one matches the hash:
var hashRegex = new RegExp("^.*\\?v=\\w{5}$");
But I'm trying to extend that one to include "/static/js".
I tried:
var hashRegex = new RegExp("^.*\/static\/js\/.*\\?v=\\w{5}$");
But doesn't seems to work.
What am I missing?
In javascript when regex is represented using string you need to double escape(\\) the special character(of regex)
So,your regex would be
var hashRegex = new RegExp("^.*/static/js/.*\\?v=\\w{5}$");
But if you use this syntax for regex
var hashRegex = /regex/;
you have to escape with single \.You would also escape / since it is used as a delimiter
So,your regex in this case would be
var hashRegex = /^.*\/static\/js\/.*\?v=\w{5}$/;
I would try this:
var hashRegex = new RegExp("^.*\/static\/js\/.*\?v\=[a-zA-Z0-9]{5}$");
( I don't know if you have to escape the = )

JavaScript regular expression to match hyphenated words?

I'd like a JavaScript regular expression that can match a string either at the start of another string, or after a hyphen in the string.
For example, "milne" and "lee" and "lees" should all match "Lees-Milne".
This is my code so far:
var name = "Lees-Milne";
var text = "lee";
// I don't know what 'text' is ahead of time, so
// best to use RegExp constructor.
var re = RegExp("^" + text | "-" + text, "i");
alert(re.exec(name.toLowerCase()));
However, this returns null. What am I doing wrong?
You could also use:
var re = RegExp("(?:^|-)" + text, "i");
Don't forget to escape regex meta characters in text if it's not an expression it self.
JavaScript has no built in function for that, but you could use:
function quotemeta(str){
return str.replace(/[.+*?|\\^$(){}\[\]-]/g, '\\$&');
}

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