I have regex string /^(?:\[)(.*)(?:\|)(.*)(?:\|)(.*)(?:\|)(.*)(?:\|)(.*)(?:\])$/ that captures the following value [john|doe|doe#email.com|doe_avatar|manager].
I also like to capture the value with [john|doe|doe#email.com|doe_avatar] using the same regex for both. How can I do that in Javascript?
Yes, this is doable with a single regex, by enclosing the last segment and its accompanying pipe \| in an additional, optional, non-capturing group ((?:……)?).
const regex =
/^(?:\[)(.*?)(?:\|)(.*?)(?:\|)(.*?)(?:\|)(.*?)(?:(?:\|)(.*?))?(?:\])$/
const rows = [
'[john|doe|doe#email.com|doe_avatar|manager]',
'[jane|doe|jane#email.com|jane_avatar]',
]
const parse = str => {
const m = str.match(regex)
if (!m) return null
const [fullMatch, forename, surname, email, avatar, role] = m
return { fullMatch, forename, surname, email, avatar, role }
}
console.log(rows.map(parse))
As #CertainPerformance mentions below, the results from the final capturing group will be undefined if the match isn't present
If you want each section to be in a separate group, it's not possible in a single iteration of a regex pattern in JS (though it's possible in .NET and other flavors where repeated group matches can be extracted). The best you'll be able to manage is matching [ eventually followed by ], and then splitting by |s afterwards:
const extract = (str) => {
const insideBrackets = str.match(/\[([^\]]+)\]/)[1];
const sections = insideBrackets.split('|');
console.log(sections);
};
extract('[john|doe|doe#email.com|doe_avatar|manager]');
extract('[john|doe|doe#email.com|doe_avatar]');
Related
I need to replace two strings using regular expression value replacement so the resulting string is $?tlang=es&text=Hello world, so I didn't know to use here String.prototype.replace().
const value = "Hello world"
const queryString = "?tlang=es&text=$1"
In this scenary, value and queryString are hard-coded, but in "real life" it should be the result of a regular expression group capturing like line.match(/msgid \"(.*)\"/) where line is an iterated text line and queryString is what the user submitted.
I thought I just could do this, but maybe it's too much effort where there is a better solution (that I couldn't find):
const line = "Full name: John Doe" // text input
const sourcePattern = /Full name: (.*) (.*)/ // user input
let queryString = 'name=$1&lname=$2' // user input
const matches = line.match(sourcePattern)
matches.splice(0, 1)
for (let i = 0; i < matches.length; i++) {
queryString = queryString.replace(`\$${i+1}`, matches[i])
}
Any ideas?
Regular expressions are fine to extract the values from the first string. But for working with query strings there's a built in class that helps:
const entries = [...new URLSearchParams(queryString).entries()]
if (matches.length !== entries.length) {
// handle error
}
const replaced = entries.reduce((params, [key], index) => {
params.append(key, matches[index]);
return params;
}, new URLSearchParams());
You can call toString() on it to get the modified query string. Generally speaking you want to avoid doing string processing any time there's a readily available richer data type.
You could compact the code a little as follows:
const line = "Full name: John Doe" // text input
const sourcePattern = /Full name: (.*) (.*)/ // user input
let queryString = 'name=$1&lname=$2' // user input
const [_, ...matches] = line.match(sourcePattern)
console.log(queryString.split(/\$\d+/)
.map((p,i)=>`${p}${matches[i]??''}`).join(''))
This is the opposite problem to Efficient JavaScript String Replacement. That solution covers the insertion of data into placeholders whilst this question covers the matching of strings and the extraction of data from placeholders.
I have a problem in understanding how to do the following in ES6 JavaScript.
I'm trying to figure out a way to match strings with placeholders and extract the contents of the placeholders as properties of an object. Perhaps an example will help.
Given the pattern:
my name is {name} and I live in {country}
It would match the string:
my name is Mark and I live in England
And provide an object:
{
name: "Mark",
country: "England"
}
The aim is to take a string and check against a number of patterns until I get a match and then have access to the placeholder values.
Can anyone point me in the right direction...
You can use named capture groups for that problem e.g.
const string = "my name is Mark and I live in England";
const regEx = /name is\s(?<name>\w+?)\b.*?live in (?<country>\w+?)\b/i;
const match = regEx.exec(string);
console.log(match?.groups);
I would be surprised if it can be done with a regex.
The way I would think about it is as follows:
Split the template by { or }
iterate over the latter template parts (every other one starting with index 1)
In each iteration, get the key, its prefix, and postfix (or next prefix)
We can then compute the start and end indices to extract the value from the string with the help of the above.
const extract = (template, str) => {
const templateParts = template.split(/{|}/);
const extracted = {};
for (let index = 1; index < templateParts.length; index += 2) {
const
possibleKey = templateParts[index],
keyPrefix = templateParts[index - 1],
nextPrefix = templateParts[index + 1];
const substringStartIndex = str.indexOf(keyPrefix) + keyPrefix.length;
const substringEndIndex = nextPrefix ? str.indexOf(nextPrefix) : str.length;
extracted[possibleKey] = str.substring(substringStartIndex, substringEndIndex);
}
return extracted;
}
console.log( extract('my name is {name} and I live in {country}', 'my name is Mark and I live in England') );
I have the following string
"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,
I need to get string after "ssu":" the Result should be 89c4eef0-3a0d-47ae-a97f-42adafa7cf8f. How do I do it in Javascript but very simple? I am thinking to collect 36 character after "ssu":".
You could build a valid JSON string and parse it and get the wanted property ssu.
var string = '"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,',
object = JSON.parse(`{${string.slice(0, -1)}}`), // slice for removing the last comma
ssu = object.ssu;
console.log(ssu);
One solution would be to use the following regular expression:
/\"ssu\":\"([\w-]+)\"/
This pattern basically means:
\"ssu\":\" , start searching from the first instance of "ssu":"
([\w-]+) , collect a "group" of one or more alphanumeric characters \w and hypens -
\", look for a " at the end of the group
Using a group allows you to extract a portion of the matched pattern via the String#match method that is of interest to you which in your case is the guid that corresponds to ([\w-]+)
A working example of this would be:
const str = `"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,`
const value = str.match(/\"ssu\":\"([\w-]+)\"/)[1]
console.log(value);
Update: Extract multiple groupings that occour in string
To extract values for multiple occurances of the "ssu" key in your input string, you could use the String#matchAll() method to achieve that as shown:
const str = `"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,"ssu":"value-of-second-ssu","ssu":"value-of-third-ssu"`;
const values =
/* Obtain array of matches for pattern */
[...str.matchAll(/\"ssu\":\"([\w-]+)\"/g)]
/* Extract only the value from pattern group */
.map(([,value]) => value);
console.log(values);
Note that for this to work as expected, the /g flag must be added to the end of the original pattern. Hope that helps!
Use this regExp: /(?!"ssu":")(\w+-)+\w+/
const str = '"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,';
const re = /(?!"ssu":")(\w+-)+\w+/;
const res = str.match(re)[0];
console.log(res);
You can use regular expressions.
var str = '"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,'
var minhaRE = new RegExp("[a-z|0-9]*-[a-z|0-9|-]*");
minhaRE.exec(str)
OutPut: Array [ "89c4eef0-3a0d-47ae-a97f-42adafa7cf8f" ]
Looks almost like a JSON string.
So with a small change it can be parsed to an object.
var str = '"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049, ';
var obj = JSON.parse('{'+str.replace(/[, ]+$/,'')+'}');
console.log(obj.ssu)
I'm trying to match a certain word on a string and only if it doesn't exist i want to match the another one using the OR | operator ....but the match is ignoring that... how can i insure that the behavior works :
const str = 'Soraka is an ambulance 911'
const regex = RegExp('('+'911'+'|'+'soraka'+')','i')
console.log(str.match(regex)[0]) // should get 911 instead
911 occurs late in the string, whereas Soraka occurs earlier, and the regex engine iterates character-by-character, so Soraka gets matched first, even though it's on the right-hand side of the alternation.
One option would be to match Soraka or 911 in captured lookaheads instead, and then with the regex match object, alternate between the two groups to get the one which is not undefined:
const check = (str) => {
const regex = /^(?=.*(911)|.*(Soraka))/;
const match = str.match(regex);
console.log(match[1] || match[2]);
};
check('Soraka is an ambulance 911');
check('foo 911');
check('foo Soraka');
You can use includes and find
You can pass the strings in the priority sequence, so as soon as find found any string in the original string it returns that strings back,
const str = 'Soraka is an ambulance 911'
const findStr = (...arg) => {
return [...arg].find(toCheck => str.includes(toCheck))
}
console.log(findStr("911", "Soraka"))
You can extend the findStr if you want your match to be case insensitive something like this
const str = 'Soraka is an ambulance 911'
const findStr = (...arg) => {
return [...arg].find(toCheck => str.toLowerCase().includes(toCheck.toLowerCase()))
}
console.log(findStr("Soraka", "911"))
If you want match to be whole word not the partial words than you can build dynamic regex and use it search value
const str = '911234 Soraka is an ambulance 911'
const findStr = (...arg) => {
return [...arg].find(toCheck =>{
let regex = new RegExp(`\\b${toCheck}\\b`,'i')
return regex.test(str)
})
}
console.log(findStr("911", "Soraka"))
Just use a greedy dot before a capturing group that matches 911 or Soraka:
/.*(911)|(Soraka)/
See the regex demo
The .* (or, if there are line breaks, use /.*(911)|(Soraka)/s in Chrome/Node, or /[^]*(911)|(Soraka)/ to support legacy EMCMScript versions) will ensure the regex index advances to the rightmost position when matching 911 or Soraka.
JS demo (borrowed from #CertainPerformance's answer):
const check = (str) => {
const regex = /.*(911)|(Soraka)/;
const match = str.match(regex) || ["","NO MATCH","NO MATCH"];
console.log(match[1] || match[2]);
};
check('Soraka is an ambulance 911');
check('Ambulance 911, Soraka');
check('foo 911');
check('foo Soraka');
check('foo oops!');
i'm trying to check wether a string matches a set of values and they are seperated by a ; It needs to have ; as a separator.
I go this new RegExp(/\b(Segunda|Terça|Quarta|Quinta|Sexta|Sábado|Domingo)\b/, 'gi').test(str)
If i pass:
'Segunda;Terça', true.
'Segundaaa', false.
'Segunda;Terçaa', true.. Why is it true? how can i avoid this?
Thanks in advance.
[EDIT] code:
const WEEK_DAYS_GROUP_REGEX = /\b(Segunda|Terça|Quarta|Quinta|Sexta|Sábado|Domingo)\b/;
const res = new RegExp(WEEK_DAYS_GROUP_REGEX, 'i').test('Segunda;Terçaa');
console.log(res) // gives true
The /\b(Segunda|Terça|Quarta|Quinta|Sexta|Sábado|Domingo)\b/ pattern with gi modifiers matches any of the alternatives as a whole word, it does not guarantee that the whole string consists of these values only, let alone the ; delimiter.
You may use
^(<ALTERNATIONS>)(?:;(<ALTERNATIONS>))*$
See the pattern demo.
In JS, you do not need to use that long pattern, you may build the pattern dynamically:
const strs = ["Segunda;Terça", "Segundaaa", "Segunda;Terçaa"];
const vals = "Segunda|Terça|Quarta|Quinta|Sexta|Sábado|Domingo";
let rx = new RegExp("^(?:" + vals + ")(?:;(?:" + vals + "))*$", "i");
console.log(rx);
for (let s of strs) {
console.log(s,"=>",rx.test(s));
}
Note that the non-capturing groups (?:...) are preferred when there is no need extracting submatches, group values.