I am trying to do the following with no avail: There are a few scenarios where self.name has a erroneous '/' in the middle of the value; ie. populating as such 'WSDH/222-310' - I am trying to simply catch this and convert it for the value to resolve in my following .load call as 'WSDH-222-310'
if (self.type === "car") {
var carClean = ${self.name}; // returns syntax error
var res = str.replace("/", "-");
console.log(carClean )
console.log(res)
// console.log({self.type});
}
self.$container.load(`view/coolObjects/${self.type}/${self.name}`, loadProfile);
I think there's a use case for a tagged template if all embedded variables should be escaped.
A more advanced form of template literals are tagged templates. Tags allow you to parse template literals with a function. The first argument of a tag function contains an array of string values. The remaining arguments are related to the expressions. In the end, your function can return your manipulated string
Example:
var path = `foo/${x}/${y}/bar`;
If both x and y should be escaped so as to replace '/' with '-', then you could do this:
const sanitize_path = (strings, ...parts) =>
strings
.flatMap((str, idx) =>
[ str,
idx < parts.length
? parts[idx].replace(/\//g, '-')
: '' ])
.join('');
const x = '1/2/3';
const y = 'y';
console.log(
sanitize_path`foo/${x}/${y}/bar`
);
Why bother cleaning the strings before using them?
I'm not clear on exactly what you're trying to do, but you can "clean" on the fly like this:
self.$container.load(`view/coolObjects/${self.type}/${self.name.replace("/","-")}`, loadProfile);
Whether or not your surrounding code works, I can't tell. But here's a working sample of what I'm suggesting:
let self = {"type":"mytype","name":"myname"};
console.log(`view/coolObjects/${self.type}/${self.name.replace("my","your")}`);
If I understand your question correctly then you're on the right track using String.prototype.replace - should be something simple as this:
var self = {
name: 'WSDH/222-310'
};
self.name = self.name.replace('/', '-');
console.dir(self);
Related
I am designing a regular expression tester in HTML and JavaScript. The user will enter a regex, a string, and choose the function they want to test with (e.g. search, match, replace, etc.) via radio button and the program will display the results when that function is run with the specified arguments. Naturally there will be extra text boxes for the extra arguments to replace and such.
My problem is getting the string from the user and turning it into a regular expression. If I say that they don't need to have //'s around the regex they enter, then they can't set flags, like g and i. So they have to have the //'s around the expression, but how can I convert that string to a regex? It can't be a literal since its a string, and I can't pass it to the RegExp constructor since its not a string without the //'s. Is there any other way to make a user input string into a regex? Will I have to parse the string and flags of the regex with the //'s then construct it another way? Should I have them enter a string, and then enter the flags separately?
Use the RegExp object constructor to create a regular expression from a string:
var re = new RegExp("a|b", "i");
// same as
var re = /a|b/i;
var flags = inputstring.replace(/.*\/([gimy]*)$/, '$1');
var pattern = inputstring.replace(new RegExp('^/(.*?)/'+flags+'$'), '$1');
var regex = new RegExp(pattern, flags);
or
var match = inputstring.match(new RegExp('^/(.*?)/([gimy]*)$'));
// sanity check here
var regex = new RegExp(match[1], match[2]);
Here is a one-liner: str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
I got it from the escape-string-regexp NPM module.
Trying it out:
escapeStringRegExp.matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
function escapeStringRegExp(str) {
return str.replace(escapeStringRegExp.matchOperatorsRe, '\\$&');
}
console.log(new RegExp(escapeStringRegExp('example.com')));
// => /example\.com/
Using tagged template literals with flags support:
function str2reg(flags = 'u') {
return (...args) => new RegExp(escapeStringRegExp(evalTemplate(...args))
, flags)
}
function evalTemplate(strings, ...values) {
let i = 0
return strings.reduce((str, string) => `${str}${string}${
i < values.length ? values[i++] : ''}`, '')
}
console.log(str2reg()`example.com`)
// => /example\.com/u
Use the JavaScript RegExp object constructor.
var re = new RegExp("\\w+");
re.test("hello");
You can pass flags as a second string argument to the constructor. See the documentation for details.
In my case the user input somethimes was sorrounded by delimiters and sometimes not. therefore I added another case..
var regParts = inputstring.match(/^\/(.*?)\/([gim]*)$/);
if (regParts) {
// the parsed pattern had delimiters and modifiers. handle them.
var regexp = new RegExp(regParts[1], regParts[2]);
} else {
// we got pattern string without delimiters
var regexp = new RegExp(inputstring);
}
Try using the following function:
const stringToRegex = str => {
// Main regex
const main = str.match(/\/(.+)\/.*/)[1]
// Regex options
const options = str.match(/\/.+\/(.*)/)[1]
// Compiled regex
return new RegExp(main, options)
}
You can use it like so:
"abc".match(stringToRegex("/a/g"))
//=> ["a"]
Here is my one liner function that handles custom delimiters and invalid flags
// One liner
var stringToRegex = (s, m) => (m = s.match(/^([\/~#;%#'])(.*?)\1([gimsuy]*)$/)) ? new RegExp(m[2], m[3].split('').filter((i, p, s) => s.indexOf(i) === p).join('')) : new RegExp(s);
// Readable version
function stringToRegex(str) {
const match = str.match(/^([\/~#;%#'])(.*?)\1([gimsuy]*)$/);
return match ?
new RegExp(
match[2],
match[3]
// Filter redundant flags, to avoid exceptions
.split('')
.filter((char, pos, flagArr) => flagArr.indexOf(char) === pos)
.join('')
)
: new RegExp(str);
}
console.log(stringToRegex('/(foo)?\/bar/i'));
console.log(stringToRegex('#(foo)?\/bar##gi')); //Custom delimiters
console.log(stringToRegex('#(foo)?\/bar##gig')); //Duplicate flags are filtered out
console.log(stringToRegex('/(foo)?\/bar')); // Treated as string
console.log(stringToRegex('gig')); // Treated as string
I suggest you also add separate checkboxes or a textfield for the special flags. That way it is clear that the user does not need to add any //'s. In the case of a replace, provide two textfields. This will make your life a lot easier.
Why? Because otherwise some users will add //'s while other will not. And some will make a syntax error. Then, after you stripped the //'s, you may end up with a syntactically valid regex that is nothing like what the user intended, leading to strange behaviour (from the user's perspective).
This will work also when the string is invalid or does not contain flags etc:
function regExpFromString(q) {
let flags = q.replace(/.*\/([gimuy]*)$/, '$1');
if (flags === q) flags = '';
let pattern = (flags ? q.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1') : q);
try { return new RegExp(pattern, flags); } catch (e) { return null; }
}
console.log(regExpFromString('\\bword\\b'));
console.log(regExpFromString('\/\\bword\\b\/gi'));
Thanks to earlier answers, this blocks serves well as a general purpose solution for applying a configurable string into a RegEx .. for filtering text:
var permittedChars = '^a-z0-9 _,.?!#+<>';
permittedChars = '[' + permittedChars + ']';
var flags = 'gi';
var strFilterRegEx = new RegExp(permittedChars, flags);
log.debug ('strFilterRegEx: ' + strFilterRegEx);
strVal = strVal.replace(strFilterRegEx, '');
// this replaces hard code solt:
// strVal = strVal.replace(/[^a-z0-9 _,.?!#+]/ig, '');
You can ask for flags using checkboxes then do something like this:
var userInput = formInput;
var flags = '';
if(formGlobalCheckboxChecked) flags += 'g';
if(formCaseICheckboxChecked) flags += 'i';
var reg = new RegExp(userInput, flags);
Safer, but not safe. (A version of Function that didn't have access to any other context would be good.)
const regexp = Function('return ' + string)()
I found #Richie Bendall solution very clean. I added few small modifications because it falls appart and throws error (maybe that's what you want) when passing non regex strings.
const stringToRegex = (str) => {
const re = /\/(.+)\/([gim]?)/
const match = str.match(re);
if (match) {
return new RegExp(match[1], match[2])
}
}
Using [gim]? in the pattern will ignore any match[2] value if it's invalid. You can omit the [gim]? pattern if you want an error to be thrown if the regex options is invalid.
I use eval to solve this problem.
For example:
function regex_exec() {
// Important! Like #Samuel Faure mentioned, Eval on user input is a crazy security risk, so before use this method, please take care of the security risk.
var regex = $("#regex").val();
// eval()
var patt = eval(userInput);
$("#result").val(patt.exec($("#textContent").val()));
}
Normal String assignment:
var str1 = "\320";
console.log(str1); // "Ð"
Raw String assignment:
var str2 = String.raw`\320`;
console.log(str2); // "\320"
In raw string, the backslashes are not interpreted. I need to interpret them so that "\320" will become "Ð". Should I have to convert the raw string to normal String. If so, How? If not so, what else should I do and how do I do?
The thing is, this code is octal, and since these are mapped with linguistic symbols, javascript interpretes it when defining new string.
what you can do is make a map of all the symbols you require with their key as actual string and value as actual symbol.
for ex -
var map = {
"\\320": "\320"
}
console.log(map);
now you can search you text in the map and get the required value.
var str2 = String.raw`\320`;
var s = map[str2];
console.log(s);
to make the map, try this -
visit this site - https://brajeshwar.github.io/entities/
and run this code on console
// for latin
var tbody = document.getElementById("latin");
var trs = tbody.children;
var map = {};
for(i=1;i<trs.length;i++) {
console.log(trs[i].children[6].innerText);
key = trs[i].children[6].innerText;
value = trs[i].children[1].innerText;
map[key] = value;
}
now console map, stringify it, and paste the string in your code and parse it.
I have done this only for latin, similarly do this for other elements also.
Question is a couple of months old, but I think this answer is your best bet, yet. Transforming escape sequences from raw strings is very much doable with ES6 String.fromcodepoint(<hex-value>). I'm in the middle of writing an NPM package which deals with this exact scenario.
First, you need a regular expression which matches all escape sequences in your string. I've used this as a reference for all the different ones. (I use a raw string for this to avoid spamming backslashes)
let [single, ...hex] = String.raw`
\\[bfnrtv0'"\\]
\\x[a-fA-F0-9]{2}
(\\u[a-fA-F0-9]{4}){1,}
\\u\{([0-9a-fA-F]{1,})\}`
.split("\n").slice(1).map(cur => cur.trim());
let escapes = new RegExp(`(${[single].concat(hex).join("|")})`, "gm"),
// We need these for later when differentiating how we convert the different escapes.
uniES6 = new RegExp(`${hex.pop()}`);
single = new RegExp(`${single}`);
Now you can match all the escapes; reserved single characters, extended ASCII range, ES6 "Astral" unicode hexadecimals and surrogate pairs. (except octals because they're deprecated, but you can always add it back). The next step is writing a function which can replace the code points with the corresponding symbols. First a switch-like function for singles:
const singleEscape = seq =>
(() => ({
"\\b" : "\b",
"\\f" : "\f",
"\\n" : "\n",
"\\r" : "\r",
"\\t" : "\t",
"\\v" : "\v",
"\\0" : "\0",
"\\'" : "\'",
"\\\"" : "\"",
"\\\\" : "\\"
}[seq]))();
Then we can rely on ES6 fromcodepoint to deal with the rest which are all hexadecimals.
const convertEscape = seq => {
if (single.test(seq))
return singleEscape(seq);
else if (uniES6.test(seq))
return String.fromCodePoint(`0x${seq.split("").slice(3, -1).join("")}`);
else
return String.fromCodePoint.apply(
String, seq.split("\\").slice(1).map(pt => `0x${pt.substr(1)}`)
);
}
Lastly, we tie it all together with a tagged template literal function named normal. I do not know why you need a raw string, but here you can have access to the raw string and put any additional logic while still resulting in a string where escape sequences are properly parsed.
const normal = (strings, ...values) => strings.raw
.reduce((acc, cur, i) => acc += (values[i-1] || "") + cur, "")
.replace(escapes, match => convertEscape(match));
I am designing a regular expression tester in HTML and JavaScript. The user will enter a regex, a string, and choose the function they want to test with (e.g. search, match, replace, etc.) via radio button and the program will display the results when that function is run with the specified arguments. Naturally there will be extra text boxes for the extra arguments to replace and such.
My problem is getting the string from the user and turning it into a regular expression. If I say that they don't need to have //'s around the regex they enter, then they can't set flags, like g and i. So they have to have the //'s around the expression, but how can I convert that string to a regex? It can't be a literal since its a string, and I can't pass it to the RegExp constructor since its not a string without the //'s. Is there any other way to make a user input string into a regex? Will I have to parse the string and flags of the regex with the //'s then construct it another way? Should I have them enter a string, and then enter the flags separately?
Use the RegExp object constructor to create a regular expression from a string:
var re = new RegExp("a|b", "i");
// same as
var re = /a|b/i;
var flags = inputstring.replace(/.*\/([gimy]*)$/, '$1');
var pattern = inputstring.replace(new RegExp('^/(.*?)/'+flags+'$'), '$1');
var regex = new RegExp(pattern, flags);
or
var match = inputstring.match(new RegExp('^/(.*?)/([gimy]*)$'));
// sanity check here
var regex = new RegExp(match[1], match[2]);
Here is a one-liner: str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
I got it from the escape-string-regexp NPM module.
Trying it out:
escapeStringRegExp.matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
function escapeStringRegExp(str) {
return str.replace(escapeStringRegExp.matchOperatorsRe, '\\$&');
}
console.log(new RegExp(escapeStringRegExp('example.com')));
// => /example\.com/
Using tagged template literals with flags support:
function str2reg(flags = 'u') {
return (...args) => new RegExp(escapeStringRegExp(evalTemplate(...args))
, flags)
}
function evalTemplate(strings, ...values) {
let i = 0
return strings.reduce((str, string) => `${str}${string}${
i < values.length ? values[i++] : ''}`, '')
}
console.log(str2reg()`example.com`)
// => /example\.com/u
Use the JavaScript RegExp object constructor.
var re = new RegExp("\\w+");
re.test("hello");
You can pass flags as a second string argument to the constructor. See the documentation for details.
In my case the user input somethimes was sorrounded by delimiters and sometimes not. therefore I added another case..
var regParts = inputstring.match(/^\/(.*?)\/([gim]*)$/);
if (regParts) {
// the parsed pattern had delimiters and modifiers. handle them.
var regexp = new RegExp(regParts[1], regParts[2]);
} else {
// we got pattern string without delimiters
var regexp = new RegExp(inputstring);
}
Try using the following function:
const stringToRegex = str => {
// Main regex
const main = str.match(/\/(.+)\/.*/)[1]
// Regex options
const options = str.match(/\/.+\/(.*)/)[1]
// Compiled regex
return new RegExp(main, options)
}
You can use it like so:
"abc".match(stringToRegex("/a/g"))
//=> ["a"]
Here is my one liner function that handles custom delimiters and invalid flags
// One liner
var stringToRegex = (s, m) => (m = s.match(/^([\/~#;%#'])(.*?)\1([gimsuy]*)$/)) ? new RegExp(m[2], m[3].split('').filter((i, p, s) => s.indexOf(i) === p).join('')) : new RegExp(s);
// Readable version
function stringToRegex(str) {
const match = str.match(/^([\/~#;%#'])(.*?)\1([gimsuy]*)$/);
return match ?
new RegExp(
match[2],
match[3]
// Filter redundant flags, to avoid exceptions
.split('')
.filter((char, pos, flagArr) => flagArr.indexOf(char) === pos)
.join('')
)
: new RegExp(str);
}
console.log(stringToRegex('/(foo)?\/bar/i'));
console.log(stringToRegex('#(foo)?\/bar##gi')); //Custom delimiters
console.log(stringToRegex('#(foo)?\/bar##gig')); //Duplicate flags are filtered out
console.log(stringToRegex('/(foo)?\/bar')); // Treated as string
console.log(stringToRegex('gig')); // Treated as string
I suggest you also add separate checkboxes or a textfield for the special flags. That way it is clear that the user does not need to add any //'s. In the case of a replace, provide two textfields. This will make your life a lot easier.
Why? Because otherwise some users will add //'s while other will not. And some will make a syntax error. Then, after you stripped the //'s, you may end up with a syntactically valid regex that is nothing like what the user intended, leading to strange behaviour (from the user's perspective).
This will work also when the string is invalid or does not contain flags etc:
function regExpFromString(q) {
let flags = q.replace(/.*\/([gimuy]*)$/, '$1');
if (flags === q) flags = '';
let pattern = (flags ? q.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1') : q);
try { return new RegExp(pattern, flags); } catch (e) { return null; }
}
console.log(regExpFromString('\\bword\\b'));
console.log(regExpFromString('\/\\bword\\b\/gi'));
Thanks to earlier answers, this blocks serves well as a general purpose solution for applying a configurable string into a RegEx .. for filtering text:
var permittedChars = '^a-z0-9 _,.?!#+<>';
permittedChars = '[' + permittedChars + ']';
var flags = 'gi';
var strFilterRegEx = new RegExp(permittedChars, flags);
log.debug ('strFilterRegEx: ' + strFilterRegEx);
strVal = strVal.replace(strFilterRegEx, '');
// this replaces hard code solt:
// strVal = strVal.replace(/[^a-z0-9 _,.?!#+]/ig, '');
You can ask for flags using checkboxes then do something like this:
var userInput = formInput;
var flags = '';
if(formGlobalCheckboxChecked) flags += 'g';
if(formCaseICheckboxChecked) flags += 'i';
var reg = new RegExp(userInput, flags);
Safer, but not safe. (A version of Function that didn't have access to any other context would be good.)
const regexp = Function('return ' + string)()
I found #Richie Bendall solution very clean. I added few small modifications because it falls appart and throws error (maybe that's what you want) when passing non regex strings.
const stringToRegex = (str) => {
const re = /\/(.+)\/([gim]?)/
const match = str.match(re);
if (match) {
return new RegExp(match[1], match[2])
}
}
Using [gim]? in the pattern will ignore any match[2] value if it's invalid. You can omit the [gim]? pattern if you want an error to be thrown if the regex options is invalid.
I use eval to solve this problem.
For example:
function regex_exec() {
// Important! Like #Samuel Faure mentioned, Eval on user input is a crazy security risk, so before use this method, please take care of the security risk.
var regex = $("#regex").val();
// eval()
var patt = eval(userInput);
$("#result").val(patt.exec($("#textContent").val()));
}
disclaimer - absolutely new to regexes....
I have a string like this:
subject=something||x-access-token=something
For this I need to extract two values. Subject and x-access-token.
As a starting point, I wanted to collect two strings: subject= and x-access-token=. For this here is what I did:
/[a-z,-]+=/g.exec(mystring)
It returns only one element subject=. I expected both of them. Where i am doing wrong?
The g modifier does not affect exec, because exec only returns the first match by specification. What you want is the match method:
mystring.match(/[a-z,-]+=/g)
No regex necessary. Write a tiny parser, it's easy.
function parseValues(str) {
var result = {};
str.split("||").forEach(function (item) {
var parts = item.split("=");
result[ parts[0] /* key */ ] = parts[1]; /* value */
});
return result;
}
usage
var obj = parseValues("subject=something||x-access-token=something-else");
// -> {subject: "something", x-access-token: "something-else"}
var subj = obj.subject;
// -> "something"
var token = obj["x-access-token"];
// -> "something-else"
Additional complications my arise when there is an escaping schema involved that allows you to have || inside a value, or when a value can contain an =.
You will hit these complications with regex approach as well, but with a parser-based approach they will be much easier to solve.
You have to execute exec twice to get 2 extracted strings.
According to MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec
If your regular expression uses the "g" flag, you can use the exec() method multiple times to find successive matches in the same string.
Usually, people extract all strings matching the pattern one by one with a while loop. Please execute following code in browser console to see how it works.
var regex = /[a-z,-]+=/g;
var string = "subject=something||x-access-token=something";
while(matched = regex.exec(string)) console.log(matched);
You can convert the string into a valid JSON string, then parse it to retrieve an object containing the expected data.
var str = 'subject=something||x-access-token=something';
var obj = JSON.parse('{"' + str.replace(/=/g, '":"').replace(/\|\|/g, '","') + '"}');
console.log(obj);
I don't think you need regexp here, just use the javascript builtin function "split".
var s = "subject=something1||x-access-token=something2";
var r = s.split('||'); // r now is an array: ["subject=something1", "x-access-token=something2"]
var i;
for(i=0; i<r.length; i++){
// for each array's item, split again
r[i] = r[i].split('=');
}
At the end you have a matrix like the following:
y x 0 1
0 subject something1
1 x-access-token something2
And you can access the elements using x and y:
"subject" == r[0][0]
"x-access-token" == r[1][0]
"something2" == r[1][1]
If you really want to do it with a pure regexp:
var input = 'subject=something1||x-access-token=something2'
var m = /subject=(.*)\|\|x-access-token=(.*)/.exec(input)
var subject = m[1]
var xAccessToken = m[2]
console.log(subject);
console.log(xAccessToken);
However, it would probably be cleaner to split it instead:
console.log('subject=something||x-access-token=something'
.split(/\|\|/)
.map(function(a) {
a = a.split(/=/);
return { key: a[0], val: a[1] }
}));
I have a string that and I am trying to extract the characters before the quote.
Example is extract the 14 from 14' - €14.99
I am using the follwing code to acheive this.
$menuItem.text().match(/[^']*/)[0]
My problem is that if the string is something like €0.88 I wish to get an empty string returned. However I get back the full string of €0.88.
What I am I doing wrong with the match?
This is the what you should use to split:
string.slice(0, string.indexOf("'"));
And then to handle your non existant value edge case:
function split(str) {
var i = str.indexOf("'");
if(i > 0)
return str.slice(0, i);
else
return "";
}
Demo on JsFiddle
Nobody seems to have presented what seems to me as the safest and most obvious option that covers each of the cases the OP asked about so I thought I'd offer this:
function getCharsBefore(str, chr) {
var index = str.indexOf(chr);
if (index != -1) {
return(str.substring(0, index));
}
return("");
}
try this
str.substring(0,str.indexOf("'"));
Here is an underscore mixin in coffescript
_.mixin
substrBefore : ->
[char, str] = arguments
return "" unless char?
fn = (s)-> s.substr(0,s.indexOf(char)+1)
return fn(str) if str?
fn
or if you prefer raw javascript : http://jsfiddle.net/snrobot/XsuQd/
You can use this to build a partial like:
var beforeQuote = _.substrBefore("'");
var hasQuote = beforeQuote("14' - €0.88"); // hasQuote = "14'"
var noQoute = beforeQuote("14 €0.88"); // noQuote = ""
Or just call it directly with your string
var beforeQuote = _.substrBefore("'", "14' - €0.88"); // beforeQuote = "14'"
I purposely chose to leave the search character in the results to match its complement mixin substrAfter (here is a demo: http://jsfiddle.net/snrobot/SEAZr/ ). The later mixin was written as a utility to parse url queries. In some cases I am just using location.search which returns a string with the leading ?.
I use "split":
let string = "one-two-three";
let um = string.split('-')[0];
let dois = string.split('-')[1];
let tres = string.split('-')[2];
document.write(tres) //three