How to match identical strings in Javascript? - javascript

Take these two urls:
const url1 = '/user/{username}/edit'
const url2 = '/user/harry/edit'
Is there a solution to match these two urls and return true as they are similar?
I tried the following and should be the worst solution:
const url1 = '/user/{username}/edit'
const url2 = '/user/harry/edit'
const split1 = url1.split('/')
const split2 = url2.split('/')
let matchCount = 0
let notMatchedCount = 0
split1.map(x => {
if(x === split2[x]) {
matchCount++
} else {
notMatchedCount++
}
})
if(matchCount > notMatchedCount) {
console.log('Match Found')
} else {
console.log('Match not found')
}
EDIT
Solution was to use PathToRegExp package! Thanks to #ChiragRavindra!

You could use a regex to test the url
\/user\/ matching /user/
\w+ matching 1 or more word characters ([a-zA-Z0-9_]+)
\/edit matching /edit
const url1 = '/user/{username}/edit';
const urlCorrect = '/user/harry/edit';
const urlWrong = '/users/harry/edit';
//generate a regex string by escaping the slashes and changing word between curly brackets with {\w+}
var regexString = url1.replace(/\{\w+\}/g, '\\w+').replace(/\//g, '\\/');
console.log('generating regex: ' + regexString);
var regex = new RegExp(regexString);
//test using the generated regex
console.log(regex.test(urlCorrect));
console.log(regex.test(urlWrong));

I would suggest you to look inside this library
NPM - String similarity library
Library simply returns the probability of comparing two strings if they're similar.
Then it's all on you to set up the threshold from how many percentages you assume that they're the same.

Related

Lowercase everything after firts appearance of the character in a string in JS

Lowercase everything after firts appearance of the character in a string in JS
One option is using regular expression:
str.replace(/\.([^.]*?)$/, (m) => m.toLowerCase())
What you can do is splitting the string at ".", then convert the last part .toLowerCase() and finally .join() everything back together.
const t = 'qwery.ABC.ABC';
const parts = t.split(".");
console.log(parts.slice(0, -1).join(".") + "." + parts[parts.length - 1].toLowerCase());
One could argue whether that would actually be a cleaner variant. What usually isn't a bad idea for code readability is writing a utility function for that use case.
const t = "qwery.ABC.ABC";
const lastBitToLowerCase = (text, separator) => {
const parts = t.split(separator);
return `${parts.slice(0, -1).join(separator)}${separator}${parts[
parts.length - 1
].toLowerCase()}`;
};
const result = lastBitToLowerCase(t, "."); // "qwery.ABC.abc"
Regex using negative lookahead:
const re = /\.((?:.(?!\.))+)$/;
const inputs = [
"qwerty.ABC.ABC",
"yuiop.uu",
"QWERT.YUIOP"
];
inputs.forEach(input => {
const result = input.replace(re, x => x.toLowerCase());
console.log(input, "-->", result);
});
Regex described here: https://regexr.com/6qk6r

Using Regex to define variables with Discord.js?

I was advised to use regex with this discord.js project. It saves two mentions from a message into two variables in the order the two mentions are typed. Discord.js reads mentions in the numeric order of the actual IDs, not the actual typed order, so we have to use regex instead. The command string is: f$command #user1 #user2
So, here's my code:
else if (command === 'command'){
const regex = /<#!?(\d+)>/;
let match = regex.exec(message);
while (match){
const User1 = match[1].id;
const User2 = match[2].id;
}
Is this correct, and how do I make it require 2 regex matches?
else if (command === 'command') {
const regex = /<#!?(\d+)>/;
let match = regex.exec(message);
const result = [];
while (match){
result.push(match[1]);
match = regex.exec(message);
}
if (result.length !== 2) {
console.error('not 2 matches');
}
const User1 = result[0];
const User2 = result[1];
}

Overlapping named capturing groups

I'm using named capturing groups to validate and extract data out of a product number. The format of the product number looks like this:
1102961D048.075
Chars 1-2 gender_code 11
Chars 1-6 style 110296
Chars 7-8 width_code 1D
Chars 9-11 color_code 048
Char 12 delimiter ignored
Chars 13-15 size_code 075
My current code looks like this:
const validateMpn = (mpn) => {
const regex = /(?<style>\d{6})(?<width>\d{1}[ABDE])(?<color_code>\d{3})\.(?<size_code>\d{3})/gi
const match = regex.exec(mpn)
if (!match) {
return null
}
return match.groups
}
const str1 = '1102961D048.075'
const str2 = '1200322A001.085'
const match1 = validateMpn(str1)
const match2 = validateMpn(str2)
console.log(match1)
console.log(match2)
As gender_code and style overlap I'm not sure how to get them both. Therefore I have the following questions:
Is it possible to this with only one regular expression?
If yes, how could I accomplish this?
Sure, just place gender inside the style group:
const validateMpn = (mpn) => {
const regex = /(?<style>(?<gender>\d{2})\d{4})(?<width>\d{1}[ABDE])(?<color_code>\d{3})\.(?<size_code>\d{3})/gi
const match = regex.exec(mpn)
if (!match) {
return null
}
return match.groups
}
const str1 = '1102961D048.075'
const str2 = '1200322A001.085'
const match1 = validateMpn(str1)
const match2 = validateMpn(str2)
console.log(match1)
console.log(match2)
I suggest just having separate capture groups for the first two and four following characters. Then, form the style by just concatenating together the first two capture groups:
var input = "1102961D048.075";
var regex = /(.{2})(.{4})(.{2})(.{3}).(.{3})/g;
var match = regex.exec(input);
console.log("gender_code: " + match[1]);
console.log("style: " + match[1] + match[2]);
As a style note, I prefer not using named capture groups, because they tend to result in a bloated regex which is hard to read.
Yes you can capture gender_code using positive look ahead using this regex,
(?=(..))(\d{6})(\d{1}[ABDE])(\d{3})\.(\d{3})
Regex Demo
This is named groups regex but will only work in Chrome browser
and named capture grouping will be available in ECMAScript 2018 and is only supported in Chrome as of now.
This JS demo will work in Chrome as that is the only one as of now supporting EcmaScript2018,
const validateMpn = (mpn) => {
const regex = /(?=(?<gender_code>\d\d))(?<style>\d{6})(?<width>\d{1}[ABDE])(?<color_code>\d{3})\.(?<size_code>\d{3})/gi
const match = regex.exec(mpn)
if (!match) {
return null
}
return match.groups
}
const str1 = '1102961D048.075'
const str2 = '1200322A001.085'
const match1 = validateMpn(str1)
const match2 = validateMpn(str2)
console.log(match1)
console.log(match2)

Javascript RegEx to find string in url between slash and either comma or question mark

I'd like to have javascript return value of 'sct' or 'rain' (strip the ",20" or ",70") from urls like:
<script>
var urls = [
"https://api.weather.gov/icons/land/day/sct,20?size=medium",
"https://api.weather.gov/icons/land/day/sct?size=medium",
"https://api.weather.gov/icons/land/night/rain?size=medium",
"https://api.weather.gov/icons/land/day/rain,60/rain,70?size=medium"
];
for(var key in urls) {
console.log(get_icon(urls[key]));
}
function get_icon(text) {
/* not sure what to do here */
}
</script>
The logic would be get string after last slash and before comma or question mark. I'm struggling with the regex statement to do that.
You can use this regex with a greedy match of .* to make sure last / is matched:
/.*\/([^,?]+)/
RegEx Demo
([^,?]+) gives you string before next ? or , in a capturing group.
Code:
var urls = [
"https://api.weather.gov/icons/land/day/sct,20?size=medium",
"https://api.weather.gov/icons/land/day/sct?size=medium",
"https://api.weather.gov/icons/land/night/rain?size=medium",
"https://api.weather.gov/icons/land/day/rain,60/rain,70?size=medium"
];
for(var key in urls) {
console.log(get_icon(urls[key]));
}
function get_icon(text) {
return (text.match(/.*\/([^,?]+)/) || [null][null])[1];
}
Please check this regex. Extract group 1 :
\S+\/(\w+,\d+|\w+)\?\w+=\w+
Reply on your need, I can do:
function get_icon(text) {
var pos = text.lastIndexOf("/");
var qmark = text.lastIndexOf("?size");
var res = text.substring(pos+1, qmark);
var res = res.split(",");
if (res.length == 2)
return res[1];
else
return null;
}

remove chars in String javascript Regex

I have a chain like this of get page
file.php?Valor1=one&Valor2=two&Valor3=three
I would like to be able to delete the get request parameter with only having the value of it. for example , remove two
Result
file.php?Valor1=one&Valor3=three
Try with
stringvalue.replace(new RegExp(value+"[(&||\s)]"),'');
Here's a regular expression that matches an ampersand (&), followed by a series of characters that are not equals signs ([^=]+), an equals sign (=), the literal value two and either the next ampersand or the end of line (&|$):
/&[^=]+=two(&|$)/
let input = 'file.php?&Valor1=one&Valor2=two&Valor3=three';
let output = input.replace(/&[^=]+=two/, '');
console.log(output);
If you're getting the value to be removed from a variable:
let two = 'two';
let re = RegExp('&[^=]+=' + two + '(&|$)');
let input = 'file.php?&Valor1=one&Valor2=two&Valor3=three';
let output = input.replace(re, '');
console.log(output);
In this case, you need to make sure that your variable value does not contain any characters that have special meaning in regular expressions. If that's the case, you need to properly escape them.
Update
To address the input string in the updated question (no ampersand before first parameter):
let one = 'one';
let re = RegExp('([?&])[^=]+=' + one + '(&?|$)');
let input = 'file.php?Valor1=one&Valor2=two&Valor3=three';
let output = input.replace(re, '$1');
console.log(output);
You can use RegExp constructor, RegExp, template literal &[a-zA-Z]+\\d+=(?=${remove})${remove}) to match "&" followed by "a-z", "A-Z", followed by one or more digits followed by "", followed by matching value to pass to .replace()
var str = "file.php?&Valor1=one&Valor2=two&Valor3=three";
var re = function(not) {
return new RegExp(`&[a-zA-Z]+\\d+=(?=${not})${not}`)
}
var remove = "two";
var res = str.replace(re(remove), "");
console.log(res);
var remove = "one";
var res = str.replace(re(remove), "");
console.log(res);
var remove = "three";
var res = str.replace(re(remove), "");
console.log(res);
I think a much cleaner solution would be to use the URLSearchParams api
var paramsString = "Valor1=one&Valor2=two&Valor3=three"
var searchParams = new URLSearchParams(paramsString);
//Iterate the search parameters.
//Each element will be [key, value]
for (let p of searchParams) {
if (p[1] == "two") {
searchParams.delete(p[0]);
}
}
console.log(searchParams.toString()); //Valor1=one&Valor3=three

Categories