This question already has answers here:
How to parse a URL?
(6 answers)
How can I make part of regex optional?
(2 answers)
Closed 24 days ago.
Is it possible to parse both of these urls with a single regex?
First is in this format for a path under project:
const str1 = "https://gitlab.com/myproject/my_product/prd/projectbranch/-/tree/master/src/tools/somepath/somename"
Second is in this format for an MR:
const str2 = "https://gitlab.com/myproject/my_product/prd/projectbranch/-/merge_requests/20"
Im able to parse the first like this:
const [_, baseUrl, type, branchName, relativePath] = str1.match(/(.*)\/-\/(tree|merge_requests)\/(.+?)(?:\/(.*$))/)
But I couldnt manage to parse the first and second strings in a single regular expression.
Basically I want to do sth like this (This doesnt work):
const [_, baseUrl, type, mergeRequestNumber] = str2.match(/(.*)\/-\/(tree|merge_requests)\/(.+?)(?:\/(.*$))/)
Edit: I want mergeRequestNumberto match 20 in 2nd match without breaking the 1st match.
If you want to parse any GitLab URL, you will have to check the type to process the tokens correctly.
const GITLAB_PATH = /(.*)\/-\/(tree|merge_requests)\/(\w+)(?:\/(.*$))?/;
const parseGitLabUrl = (url) => {
const match = new URL(url).pathname.match(GITLAB_PATH);
if (!match) return null;
let [_, basePath, type, ...rest] = match;
switch (type) {
case 'merge_requests':
let mergeRequestNumber;
[mergeRequestNumber] = rest;
return { basePath, type, mergeRequestNumber };
case 'tree':
let branchName, relativePath;
[branchName, relativePath] = rest;
return { basePath, type, branchName, relativePath };
default:
return null;
}
};
const
str1 = 'https://gitlab.com/myproject/my_product/prd/projectbranch/-/tree/master/src/tools/somepath/somename',
str2 = 'https://gitlab.com/myproject/my_product/prd/projectbranch/-/merge_requests/20';
console.log(parseGitLabUrl(str1));
console.log(parseGitLabUrl(str2));
.as-console-wrapper { top: 0; max-height: 100% !important; }
Related
I have string with slash separated contains function names.
e.g.
my_doc/desktop/customer=getCustomer()/getCsvFileName()/controller=getControllerName()
Within above string I want only function name i.e. getCustomer(), getControllerName() & getCsvFileName()
I searched some regex like:
let res = myString.match(/(?<=(function\s))(\w+)/g);
but its returning result as null.
Update:
Now I want to get function names without parentheses () i.e. getCustomer, getControllerName & getCsvFileName
Please help me in this
const str = "my_doc/desktop/customer=getCustomer()/getCsvFileName()/controller=getControllerName()"
let tokens = [];
for (element of str.split("/"))
if (element.endsWith("()"))
tokens.push(element.split("=")[1] ?? element.split("=")[0])
console.log(tokens);
General idea: split the string along slashes, and for each of these tokens, if the token ends with () (as per Nick's suggestion), split the token along =. Append the second index of the token split along = if it exists, otherwise append the first.
A "smaller" version (using purely array methods) could be:
const str = "my_doc/desktop/customer=getCustomer()/getCsvFileName()/controller=getControllerName()"
let tokens = str.split("/")
.filter(element => element.endsWith("()"))
.map(element => element.split("=")[1] ?? element.split("=")[0]);
console.log(tokens);
You can split the string that has parentheses () first like /.*?\([^)]*\)/g.
This will give array of results, and after that you can iterate the array data and for each item, you can split the = and / before function name with the help of item.split(/=|\//).
Then push the filtered function name into empty array functionNames.
Working Example:
const string = `my_doc/desktop/customer=getCustomer()/getCsvFileName()/controller=getControllerName()`;
const functionNames = [];
string.match(/.*?\([^)]*\)/g).forEach(item => {
const splitString = item.split(/=|\//);
const functionName = splitString[splitString.length - 1];
functionNames.push(functionName);
});
console.log(functionNames);
As per, MDN docs the match() method returns null if it does not find a match for the provided regex in the provided search string.
The regular expression which you have provided,/(?<=(function\s))(\w+)/g matches any word that has 'function ' before it. (NOTE: a space after the word function)
Your search string my_doc/desktop/customer=getCustomer()/getCsvFileName()/controller=getControllerName() does not include 'function ' before any characters. That is why you got null as result of match() method.
let yourString = 'my_doc/desktop/customer=getCustomer()/getCsvFileName()/controller=getControllerName()';
let myReferenceString = 'SAMPLETEXTfunction sayHi()/function sayHello()';
let res = yourString.match(/(?<=(function\s))(\w+)/g);
let res2 = myReferenceString.match(/(?<=(function\s))(\w+)/g);
console.log("Result of your string", res);
console.log("Result of my string", res2);
My solution here,
let myreferenceString = 'my_doc/desktop/customer=getCustomer()/getCsvFileName()/controller=getControllerName()'
let res = myreferenceString.match(/((?<==)(\w+\(\)))|((?<=\/)(\w+\(\)))/g);
console.log("Result", res);
NOTE: I have used the 'Positive Look Behind regex operator', This is not supported in browsers like Safari and IE. Please do reasearch about this before considering this approach.
I have a sample code but I am looking for the most efficient solution. Sure I can loop twice through the array and string but I was wondering if I could just do a prefix search character per character and identify elements to be replaced. My code does not really do any of that since my regex is broken.
const dict = {
'\\iota': 'ι',
'\\nu': 'ν',
'\\omega': 'ω',
'\\\'e': 'é',
'^e': 'ᵉ'
}
const value = 'Ko\\iota\\nu\\omega L\'\\\'ecole'
const replaced = value.replace(/\b\w+\b/g, ($m) => {
console.log($m)
const key = dict[$m]
console.log(key)
return (typeof key !== 'undefined') ? key : $m
})
Your keys are not fully word characters, so \b\w+\b will not match them. Construct the regex from the keys instead:
// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
const escapeRegExp = string => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const dict = {
'\\iota': 'ι',
'\\nu': 'ν',
'\\omega': 'ω',
'\\\'e': 'é',
'^e': 'ᵉ'
}
const value = 'Ko\\iota\\nu\\omega L\'\\\'ecole'
const pattern = new RegExp(Object.keys(dict).map(escapeRegExp).join('|'), 'g');
const replaced = value.replace(pattern, match => dict[match]);
console.log(replaced);
This question already has answers here:
Template literal inside of the RegEx
(2 answers)
Closed 2 years ago.
I’m trying to use a variable in a RegEx and I’m having problems. This is my function:
const truncateNum = (num, place = 2) => {
const matcher = `/^-?\d+(?:\.\d{0,${place}})?/`;
const re = new RegExp(matcher);
return num.toString().match(re)[0];
};
When running this I get the following error:
Uncaught TypeError: Cannot read property '0' of null
What am I doing wrong here?
There are a few issues with your code.
The first is that when you define a regex as a string, it doesn't require // marks, and also backslashes need to be double escaped \\d+.
The second is that num.toString().match(re) will return null if the regular expression doesn't match, thus you are getting an exception from trying to do an array lookup on null[0].
let truncateNum = (num, place = 2) => {
const matcher = `^-?\\d+(?:\\.\\d{0,${place}})?`; console.log(matcher);
const re = new RegExp(matcher);
const match = num.toString().match(re);
const result = match && match[0] || '0'
return result;
};
This question already has answers here:
Replace multiple strings with multiple other strings
(27 answers)
Closed 3 years ago.
I have a string prototype whose code is given below:
String.prototype.replaceAll = function(str1, str2, ignore) {
return this.replace(
new RegExp(
str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"
):str2
)};
Usage:
var a = "I am Javascript";
console.log(
a.replaceAll("am", "love")
); // => I love Javascript
But when it comes to multiple exchange of characters or words, I have to run the prototype multiple times to achieve it. But I have thought of something like this:
var a = "I am Java";
console.log(
a.replaceAll(["am" , "Java"], ["love", "Javascript"])
); // => I love Javascript
So can you help me to achieve it? Or there is any other alternative?
I'd prefer to store replacements as key-value pairs in an object or as an array of pairs. Regardless of the format, you can dynamically create a regex by joining the values you want to replace using | alternation. Then give replace a callback function and use its match parameter as a key to look up its corresponding pair in the swaps object.
const s = "I am Java";
const swaps = {am: "love", Java: "JS"};
const pattern = new RegExp(Object.keys(swaps).join("|"), "g");
console.log(s.replace(pattern, m => swaps[m]));
To handle case-insensitive replacements, ensure all keys in swaps are lowercase (either programmatically or manually, depending on usage) and lowercase the matches before keying in:
const s = "I am Java";
const swaps = {am: "love", java: "JS"};
const pattern = new RegExp(Object.keys(swaps).join("|"), "gi");
console.log(s.replace(pattern, m => swaps[m.toLowerCase()]));
This works.
String.prototype.replaceAll = function(str1, str2, ignore) {
let flags = 'g';
if (ignore) {
flags += 'i';
}
if (Array.isArray(str1) && Array.isArray(str2)) {
let newStr = this;
str1.map((element, index) => {
if (str2[index]) {
newStr = newStr.replace(new RegExp(element, flags), str2[index]);
}
return newStr;
});
return newStr;
}
else {
return this.replace(new RegExp(str1, flags), str2);
}
}
This question already has answers here:
Why do regex constructors need to be double escaped?
(5 answers)
Closed 3 years ago.
I am trying to construct regex using RegExp() based on provided string. This string is provide by a request or generated dynamic.
I have two different inputs
1) "te\*" -> which expects to remove special behavior of '*'. Expected regex output should be /te\*/g.
2) "te*" -> Which uses the special behavior of 0 or More repeating character 'e'. Expected regex output should be /te*/g.
new RegExp("te\*") -> /te*/
new RegExp("te*") -> /te*/
My first question is why the result of both inputs end up is same? I guess it may be because of escaping. Then I tried
new RegExp("te\\*") -> /te\*/
I added escaping after looking in to the doc.
var escapeString = function (string){
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
Using escape function ended up same result than different one.
escapeString("te\*") -> /te\\*/
escapeString("te*") -> /te\\*/
I tried unescaping by replacing two blackslashes by none. I am not pretty sure whether this unescaping is correct.
var unescapeString = function(string){
return string.replace(/\\\\/g,"");
}
I was wondered why didn't the regex result changed. I couldn't figure out how should make difference of those inputs?
With this behavior, I decided to try with few things like escaping and do unescaping input works or not.
1) First Input "te\*"
var unescapeString = function(string){
return string.replace(/\\\\/g,"");
}
var escapeString = function (string){
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
var aa = "te\*";
var a1_es = escapeString(aa);
aa_arr = [];
aa_arr.push(a1_es);
console.log("es1 => ", aa_arr);
var aa_es = escapeString(aa_arr[0]);
aa2_arr = [];
aa2_arr.push(aa_es);
console.log("es2 => ", aa2_arr);
var aa_ues = unescapeString(aa2_arr[0]);
aa_uesArr = [];
aa_uesArr.push(aa_ues);
console.log("ues ===>", aa_uesArr);
var rgex = new RegExp(aa_uesArr[0]);
console.log("rgex2 ===> ",rgex )
Output for above snippet:
es1 => [ 'te\\*' ]
es2 => [ 'te\\\\\\*' ]
ues ===> [ 'te\\*' ]
rgex2 ===> /te\*/
My expected output for First Input is fine.
2) Second input "te*"
var actual = "te*";
var unescapeString = function(string){
return string.replace(/\\\\/g,"");
}
var escapeString = function (string){
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
var actual_es1 = escapeString(actual);
actual1_arr = [];
actual1_arr.push(actual_es1);
console.log("es1 => ", actual1_arr);
var actual_es = escapeString(actual1_arr[0]);
actual_arr = [];
actual_arr.push(actual_es);
console.log("es2 => ", actual_arr);
var actual_ues = unescapeString(actual_es);
actual_uesArr = [];
actual_uesArr.push(actual_ues);
console.log("ues ===>", actual_uesArr);
var actualrgex = new RegExp(actual_uesArr[0]);
console.log("actualrgex ===> ",actualrgex );
Output for above snippet
es1 => [ 'te\\*' ]
es2 => [ 'te\\\\\\*' ]
ues ===> [ 'te\\*' ]
actualrgex ===> /te\*/
Expected output for Second Input Varies. It should be /te*/.
I would like to know whether am i missing something here or heading towards different direction.
I appreciate any help or suggestions of alternative approach to resolve this. Thanks for reading this long post!!!
check out first what the strings are, before building the regex
so you notice how the \* becomes a single * long before getting into the regex
and that is because of the backslash \ behavior in JavaScript Strings
var arr = ['te\*', 'te*', 'te\\*'];
arr.forEach(function(s) {
console.log('s => ', s);
});
and just in case you wanna see it in action in your code snippet:
var escapeString = function (string){
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
var arr = ['te\*', 'te*', 'te\\*'];
arr.forEach(function(s) {
console.log('s => ', s);
var es1 = escapeString(s);
console.log('es1 => ', es1);
console.log('regex1 ===> ', new RegExp(es1));
var es2 = escapeString(es1);
console.log('es2 => ', es2);
console.log('regex2 ===> ', new RegExp(es2));
});