How do I use a regular expression from a string variable - javascript

In my current project, I have a CMS that is supplying all the data. One field of that CMS is for regular expressions, which allows me to enter my own specific expressions to check in the front end. My problem is that when I pull the regular expression it is coming through the escaped characters, and I can not seem to find a way to get around this.
The expression that I am using is /^\d+$/. As I mentioned this is stored inside my CMS and I am attempting to use it in the following code:
const re = /^\d+$/;
const rea = new RegExp(this.question.QuestionExpression);
console.log(re);
console.log(rea);
console.log(this.answer)
console.log(re.test(this.answer));
console.log(rea.test(this.answer));
console.log(this.answer.toString().match(this.question.QuestionExpression))
this.question.QuestionExpression is the Regular expression that is coming in from the CMS. The problem is not getting it, but how to interperet once I have it. const re is currently just being used as a test and has no real bearing on the final outcome.
The outcome from the above code is as follows:
/^\d+$/
/\/^\d+$\//
13
true
false
null
As you can see in the second line, it is adding escape characters which are causing it to fail on the 5th line. I am sure that I am missing something simple, but any advice would be greatly appreciated.

You don't include the / at the start and end when you are using a RegExp from a string.
const pattern = new RegExp('^a.*z');
console.log(pattern.test('abcdefghijklmnopqrstuvwxyz'));
console.log(pattern.test('zydhfkjadhsfkjlahsdkla'));
So, if your string is including those slashes, or may include those slashes, simply strip them off:
const strWithSlashes = '/abc/';
const str = strWithSlashes.replace(/(^\/|\/$)/g, '');
console.log(str);
const pattern = new RegExp(str);
console.log(pattern.test('cake abc cookies'));
console.log(pattern.test('cake cookies'));

If your regex from the CMS looks like /^\d+$/ it is likely the string representation of the regex. In contrast, new RegExp() expects a string representing the regex pattern without the leading and trailing /, so you need to strip them:
const fromCMS = '/^\\d+$/'; // escaped `\` so that string becomes `/^\d+$/`
const re1 = /^\d+$/;
const re2 = new RegExp(fromCMS.replace(/^\//, '').replace(/\/$/, ''));
console.log(re1);
console.log(re2);
[ '12', '2x' ].forEach(str => {
console.log(str + ' => re1: ' + re1.test(str) + ', re2: ' + re2.test(str));
});
Output:
/^\d+$/
/^\d+$/
12 => re1: true, re2: true
2x => re1: false, re2: false
In case the regex string from the CMS contains modifiers you can extract that, and supply as a second parameter to the new RegExp()

Related

How to include a variable and exclude numbers[0-9] and letters[a-zA-Z] in RegExp?

I have a code that generates a random letter based on the word and I have tried to create a RegExp code to turn all the letters from the word to '_' except the randomly generated letter from the word.
const word = "Apple is tasty"
const randomCharacter = word[Math.floor(Math.random() * word.length)]
regex = new RegExp(/[^${randomCharacter}&\/\\#,+()$~%.'":;*?<>{}\s]/gi)
hint = word.replace(regex,'_')
I want to change all the letters to '_' except the randomly generated word. The above code for some reason does not work and shows the result: A___e __ ta_t_ and I'm not able to figure out what to do.
The final result I want is something like this: A____ __ _a___
Is there a way with regex to change all the alphabets and numbers '/[^a-zA-Z0-9]/g' to '_' except the randomly generated letter?
I'm listing all the expressions I want to include on my above code because I'm not able to figure out a way to do include and exclude at the same time using the variable with regex.
You can't do string interpolation inside of a RegExp literal (/.../). Meaning your placeholder ${randomCharacter} will not evaluate to its value in the template, but is instead interpreted literally as the string "${randomCharacter}".
If you want to use template literals, initialize your regex variable with a RegExp constructor instead, like:
const regex = new RegExp(`[^${randomCharacter}&\\/\\\#,+()$~%.'":;*?<>{}\\s]`, "gi");
See the MDN RegExp documentation for an explanation on the differences between the literal notation and constructor function, most notably:
The constructor of the regular expression object [...] results in runtime compilation of the regular expression. Use the constructor function when [...] you don't know the pattern and obtain it from another source, such as user input.
/(?:[^A\s])/
test it on regex101
just replace A in [^A\s] with you character that you want to ommit from replacement
demo:
const word = "Apple is tasty";
const randomCharacter = 'a';//word[Math.floor(Math.random() * word.length)];
regex = new RegExp('(?:[^' + randomCharacter + '\\s])', 'gi');
hint = word.replaceAll(regex, '_');
console.log(hint)

Javascipt regex to get string between two characters except escaped without lookbehind

I am looking for a specific javascript regex without the new lookahead/lookbehind features of Javascript 2018 that allows me to select text between two asterisk signs but ignores escaped characters.
In the following example only the text "test" and the included escaped characters are supposed to be selected according the rules above:
\*jdjdjdfdf*test*dfsdf\*adfasdasdasd*test**test\**sd* (Selected: "test", "test", "test\*")
During my research I found this solution Regex, everything between two characters except escaped characters /(?<!\\)(%.*?(?<!\\)%)/ but it uses negative lookbehinds which is supported in javascript 2018 but I need to support IE11 as well, so this solution doesn't work for me.
Then i found another approach which is almost getting there for me here: Javascript: negative lookbehind equivalent?. I altered the answer of Kamil Szot to fit my needs: ((?!([\\])).|^)(\*.*?((?!([\\])).|^)\*) Unfortuantely it doesn't work when two asterisks ** are in a row.
I have already invested a lot of hours and can't seem to get it right, any help is appreciated!
An example with what i have so far is here: https://www.regexpal.com/?fam=117350
I need to use the regexp in a string.replace call (str.replace(regexp|substr, newSubStr|function); so that I can wrap the found strings with a span element of a specific class.
You can use this regular expression:
(?:\\.|[^*])*\*((?:\\.|[^*])*)\*
Your code should then only take the (only) capture group of each match.
Like this:
var str = "\\*jdjdjdfdf*test*dfsdf\\*adfasdasdasd*test**test\\**sd*";
var regex = /(?:\\.|[^*])*\*((?:\\.|[^*])*)\*/g
var match;
while (match = regex.exec(str)) {
console.log(match[1]);
}
If you need to replace the matches, for instance to wrap the matches in a span tag while also dropping the asterisks, then use two capture groups:
var str = "\\*jdjdjdfdf*test*dfsdf\\*adfasdasdasd*test**test\\**sd*";
var regex = /((?:\\.|[^*])*)\*((?:\\.|[^*])*)\*/g
var result = str.replace(regex, "$1<span>$2</span>");
console.log(result);
One thing to be careful with: when you use string literals in JavaScript tests, escape the backslash (with another backslash). If you don't do that, the string actually will not have a backslash! To really get the backslash in the in-memory string, you need to escape the backslash.
const testStr = `\\*jdjdjdfdf*test*dfsdf\\*adfasdasdasd*test**test\\**sd*`;
const m = testStr.match(/\*(\\.)*t(\\.)*e(\\.)*s(\\.)*t(\\.)*\*/g).map(m => m.substr(1, m.length-2));
console.log(m);
More generic code:
const prepareRegExp = (word, delimiter = '\\*') => {
const escaped = '(\\\\.)*';
return new RegExp([
delimiter,
escaped,
[...word].join(escaped),
escaped,
delimiter
].join``, 'g');
};
const testStr = `\\*jdjdjdfdf*test*dfsdf\\*adfasdasdasd*test**test\\**sd*`;
const m = testStr
.match(prepareRegExp('test'))
.map(m => m.substr(1, m.length-2));
console.log(m);
https://instacode.dev/#Y29uc3QgcHJlcGFyZVJlZ0V4cCA9ICh3b3JkLCBkZWxpbWl0ZXIgPSAnXFwqJykgPT4gewogIGNvbnN0IGVzY2FwZWQgPSAnKFxcXFwuKSonOwogIHJldHVybiBuZXcgUmVnRXhwKFsKICAgIGRlbGltaXRlciwKICAgIGVzY2FwZWQsCiAgICBbLi4ud29yZF0uam9pbihlc2NhcGVkKSwKICAgIGVzY2FwZWQsCiAgICBkZWxpbWl0ZXIKICBdLmpvaW5gYCwgJ2cnKTsKfTsKCmNvbnN0IHRlc3RTdHIgPSBgXFwqamRqZGpkZmRmKnRlc3QqZGZzZGZcXCphZGZhc2Rhc2Rhc2QqdGVzdCoqdGVzdFxcKipzZCpgOwpjb25zdCBtID0gdGVzdFN0cgoJLm1hdGNoKHByZXBhcmVSZWdFeHAoJ3Rlc3QnKSkKCS5tYXAobSA9PiBtLnN1YnN0cigxLCBtLmxlbmd0aC0yKSk7Cgpjb25zb2xlLmxvZyhtKTs=

In JavaScript how do I get all matches using regex instead of the last one

I'm struggling to figure out how to get this regex to work without needing a loop. Here's the code that works:
var template = {name: "Oscar", anotherName: "your twin", hello: 'world'}
var str = "Hello, {{name}} I'm {{anotherName}}. Hello to the {{hello}}"
Object.keys(template).forEach(function (keyName) {
pattern = new RegExp('{{' + keyName + '}}', 'g');
str = str.replace(pattern, template[keyName]);
})
// => str "Hello, Oscar I'm your twin. Hello to the world"
The thing about this code I don't like is that it's in a loop generating regex when I feel like a regex should be able to handle this use case. However, my regex is always only matching the last item. I was doing regex like str.match(/({{.}})/gi) but then only the {{hello}} was getting matched.
Preferably I'd like to do something where I can get all matches in an array and then map the array like matchesFromRegex.map(match => template[match]).join('')
Also, I'm in an vanilla JS environment so .matchAll (which isn't supported in IE) wouldn't work.
In a RegExp string, { has a special meaning (it lets you set a cardinality for a match, like \d{5} for five digits).
Use new RegExp('\\{\\{' + keyName + '}}', 'g'); instead. The double backslash in JavaScript will create a backslash, which will escape the { character.
If you want to avoid the loop, you can use the function-based version of replace instead:
const pattern = /\{\{([^}]*)}}/g;
str.replace(pattern, (_, key) => template[key]);
To break it down, pattern has a capture group (the parts in ()). The String.prototype.replace function can let you supply a function for doing replacements, which will be passed your match results.

Regex in javascript, trying to match but doesn't seem to work with $

EDIT: This question is DIFFERENT. The regex works fine that everyone sent me. The problem is that the $ sign DOESN'T WORK on my string, but it works on others. I can't figure out why and I posted my function below.
I need to find a number at the end of a string, it will be like thisL
My Goal Amount: $25.00/$100.00.
I've tried
var matches = fileDataResult.match(/\d+$/);
but it returns null, I tried it without the $ and it returns the 25, without the .00.
How can I get a variable as a number for the first ones (25.00, with the decimals) and a different variable for the 100.00, with the decimals as well. I need the variables seperate so I can work on them, but I think regex is broken because it won't even work with the $ sign... anyone have suggestion? This is in javascript.
edit:
here is my function, it reads a .txt file and gets the string. I can console.log the string just fine and it work, but it won't work when I use $ in regex!
function fileReaderFunc(file) {
const fileReader = new FileReader();
fileReader.onload = function() {
let fileDataResult = '';
const fileData = fileReader.result;
fileDataResult = fileData.toString();
console.log(fileDataResult);
let str = fileDataResult;
let reg = /\d+(\.\d+)?$/g;
console.log(str.match(reg));
};
fileReader.readAsText(file);
}
let str = "My Goal Amount: $25.00/$100.00.";
str = str.substring(-1,str.length-1); // remove the terminal period
let reg = /\$.+\$.+$/g;
let res = str.match(reg);
let arr = res[0].split('/');
let [num1,num2] = arr;
console.log("1st: ", num1.substring(1, num1.length));
console.log("2nd: ", num2.substring(1, num2.length));
As it turns out this regex is simpler than one might suppose since the text itself includes dollar signs. One can construct a regex that searches for a literal dollar sign followed by other characters and then a second literal dollar sign also followed by other characters from the end of the string marked by a dollar sign symbol minus any slash which signifies the end of a string.
The match is stored in a result array containing one element whose string value is then split on the literal slash mark. The results are then stored in an array arr. Then the values stored in the array are assigned to variables num1 and num2 through array destructuring.
If you prefer a more focused regex, you can also code as follows:
let s = "My Goal Amount: $25.00/$100.00.";
s = s.substring(-1, s.length - 1);
let reg = /\$\d+\.\d+.\$\d+\.\d+$/;
let replaced = s.match(reg)[0].replace(/\$/g, "");
console.log(replaced.split("/"));
If you neglect to trim the string s of the terminal period, then the regex will not match with the string which results in a null. This regex specifies a pattern at the end of the string that starts with a dollar sign,followed by one or more digits then a period and one or more digits. The pattern continues with matching another character (in this case the slash mark) and then a dollar sign followed by one or more digits, next a period and again one or more digits.
First of all \d+ do not match .
You can use this
\d+(\.\d+)?$
Explanation
\d+ - Matches one or more digits.
(\.\d+)? Matches . followed by one or more digit. (? makes it optional )
let str = "abc 125.00";
let reg = /\d+(\.\d+)?$/g;
console.log(str.match(reg))

Matching a string with a regex gives null even though it should match

I am trying to get my regex to work in JavaScript, but I have a problem.
Code:
var reg = new RegExp('978\d{10}');
var isbn = '9788740013498';
var res = isbn.match(reg);
console.log(res);
However, res is always null in the console.
This is quite interesting, as the regex should work.
My question: then, what is the right syntax to match a string and a regex?
(If it matters and could have any say in the environment: this code is taken from an app.get view made in Express.js in my Node.js application)
Because you're using a string to build your regex, you need to escape the \. It's currently working to escape the d, which doesn't need escaping.
You can see what happens if you create your regex on the chrome console:
new RegExp('978\d{10}');
// => /978d{10}/
Note that there is no \d, only a d, so your regex matches 978dddddddddd. That is, the literal 'd' character repeated 10 times.
You need to use \\ to insert a literal \ in the string you're building the regex from:
var reg = new RegExp('978\\d{10}');
var isbn = '9788740013498';
var res = isbn.match(reg);
console.log(res)
// => ["9788740013498", index: 0, input: "9788740013498"]
You need to escape with double back slash if you use RegExp constructor:
var reg = new RegExp('978\\d{10}');
Quote from documentation:
When using the constructor function, the normal string escape rules (preceding special characters with \ when included in a string) are necessary. For example, the following are equivalent:
var re = /\w+/;
var re = new RegExp("\\w+");

Categories

Resources