For example:
str = "A=sample_text1; B=sample_text2; C=sample_text3;";
How can I get the text after "A=", which is "sample_text1" out ? (the length of sample_text1 can be very long, so str.substring won't work here)
Looks like your string has a structure where there are multiple fields where each field is represented as:
[KEY]=[VALUE];
You can use common string and array methods like split and map to extract what you need. In this case looks like you want the value of the first field:
const str = 'A=sample_text1; B=sample_text2; C=sample_text3;';
const result = str.split(';').map(s => s.split('=').pop().trim()).shift();
console.log(result); //=> 'sample_text1'
https://regexr.com is very useful for creating and testing regex.
const match = "A=sample_text1; B=sample_text2; C=sample_text3;".match(/A=([^;]*)/);
let value = match !== null ? match[1] : undefined;
Would allow you to get the value of A in this case
You could use a regular expression to capture every group surrounded by a = and a ;:
const str = "A=sample_text1; B=sample_text2; C=sample_text3;";
const regexp = "=(.*?);";
const values = [...str.matchAll(regexp)];
const aValue = values[0][1];
console.log(aValue);
It might be an overkill, but to easily access to all the keys / values, you could use Object.fromEntries:
let str = "A=sample_text1; B=sample_text2; C=sample_text3;";
let values = Object.fromEntries(
str
// Split all the pairs
.split(";")
// Remove the last empty element
.slice(0,-1)
// map to a [key, value] array to pass to Object.fromEntries
.map(i => i.split("=").map(j => j.trim())));
// get a value using a key
console.log(values["A"]) // sample_text1
// check if a key is present
console.log("C" in values) // true
console.log("D" in values) // false
It looks more longer than it is due the comments and the console logs, it can fit in one line.
Notice that this is assume of course that neither the character = or ; can be part of the key or the value.
Related
The following code processes a list of file paths and should return only the file names (without extension) of XML files. Currently I got to this:
const filteredFiles = files
.map(f => f.match(/.*\/(.*)\.xml/)) // map to regex match with capture
.filter(v => v) // non-matches returned null and will be filtered out here
.map(m => m[1]) // map out the regex capture
I find this code quite cumbersome. Is there no way to combine the matching and filtering in a more "efficient" way? And by "efficient" I mean code-readable-efficient and not time-efficient as the input array holds 100 values at most but most of the time between 10 and 20.
This doesn't solve your need of mapping and filtering out the non matching values in one shot... but it makes one step easier by using the optional chaining operator ?.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
I also slightly changed the regex to allow the filename with no path specifed.
const files = [
'./path/to/filename_01.xml',
'non_matching_value',
'./path/to/filename_02.xml',
'./path/to/filename_03.xml',
'./path/to/filename_04.xml',
'filename_05.xml',
];
//Approach using filter over map to ignore non matching array items
//-------------------------------------------------------------------------------
const filteredFiles = files
.map(filename => filename.match(/^(.*\/)?(.*)\.xml/)?.[2])
.filter(filename => filename);
console.log(filteredFiles);
//Approach using flatMap as suggested by another user answering the same question
//-------------------------------------------------------------------------------
const filteredFiles2 = files.flatMap((f)=>{
//here you are forced to put the match result in a dedicated variable..
const match = f.match(/^(.*\/)?(.*)\.xml/);
//because you need to use it both on the condition and the positive outcome
return ( match ) ? [match[2]] : [];
});
console.log(filteredFiles2);
//Approach using flatMap as suggested by another user answering the same question
//AND using the null coealeshing operator to return empty array in case of non matching string
//-------------------------------------------------------------------------------
const filteredFiles3 = files.flatMap(f => f.match(/^(.*\/)?(.*)\.xml/)?.[2] ?? []);
console.log(filteredFiles3);
You can (ab)use flat map:
const filteredFiles = files.flatMap((f)=>{
let match = f.match('...');
if (match) {
return [match[1]]
} else {
return []
}
})
Not sure if it's actually better than the original though.
Map and filter, otherwise known as reduce
const rx = /\/(.*)\.xml$/;
const filteredFiles = files.reduce((arr, f) => {
const match = f.match(rx);
return match ? [...arr, match[1]] : arr;
}, []);
As I added in comment, you could use reduce method of array to achieve this in single iteration
Example
const regex = /\/(.*)\.xml$/;
const filteredFiles = files.reduce((r, f) => {
const value = f.match(regex);
if (value?.[1]) {
return [...r, value[1]];//If matches found then return previous result + new value
}
return r; // If not matches found then return previous result
}, []);
I have a string that looks like this:
var str='[{"id":"abcd","pin":5},{"id":"efgh","pin":6}]';
How can i match the object-like pattern in the string. I want to retrieve {"id":"abcd","pin":"5"}
I have tried this:
str.match( new RegExp('{"id":"abcd".*}'))
unfortunately, it matches till the end of the string which is not what i desire.
I just want to retrieve
{"id":"abcd","pin":"5"} by using regexp
If you do not wish to parse the JSON, you can use the following regular expression, but keep in mind that this only works for non-nested objects.
const str = '[{"id":"abcd","pin":5},{"id":"efgh","pin":6}]';
const [found] = str.match(/\{"id":"abcd"[^\}]*\}/);
if (found) {
console.log(found); // {"id":"abcd","pin":5}
}
If you want to make this a bit more dynamic, you can try the following:
const str = '[{"id":"abcd","pin":5},{"id":"efgh","pin":6}]';
const findById = (jsonArrStr, id) =>
str.match(new RegExp(`\\{"id":"${id}"[^\\}]*\\}`))?.pop();
console.log(findById(str, 'abcd')); // {"id":"abcd","pin":5}
console.log(findById(str, 'efgh')); // {"id":"efgh","pin":6}
If you need to retrieve the object, parse it, find it, and reserialize it.
const findBy = (jsonArrStr, predicate) =>
JSON.stringify(JSON.parse(jsonArrStr).find(predicate));
const str = '[{"id":"abcd","pin":5},{"id":"efgh","pin":6}]';
const found = findBy(str, ({ id }) => id === 'abcd');
console.log(found); // {"id":"abcd","pin":5}
I want to validate a pandas formula that is getting inputted to my frontend by the end-user:
This along with a dummy data containing csv is sent to the backend where these formulaes are parsed using eval function in a try-catch block and if the system catches any error a response is returned accordingly.
What I am interested in doing is from an input string that looks something like this:
"csv['Date']+env['filename']+csv['Spend']"
and an array that looks something like this:
const locatedDfs = ['csv','env']
I want to create a dictionary/object that looks something like this:
{
csv: {Date:'',Spend:''},
env: {filename: ''}
}
What the above function does is basically scans the entire string with respect to the locatedDfs array/list and checks if there are any keys for the same and if a key exists, then it initializes that pair with an empty string.
You can use a regular expression that separates the matching results in two groups, the key and the value
const data = "csv['Date']+env['filename']+csv['Spend']+test['123_abc']";
const locatedDfs = ['csv','env'];
// 1. Create a regex that matches: $1['$2']
const regex = /(\w+)\[\'(\w+)\'\]/gm;
// 2. Create an empty object to store the results.
const result = {};
// Start searching the regex in the data
let match = regex.exec(data);
do {
// The match will return an array with 3 values
//
// [0] => The complete match, for example: csv['Date']
// [1] => The first match group (\w+) or $1: csv
// [2] => The second match group ['(\w+)'] or $2: Date
//
// Using array destruction we can store it as variables
const [, key, value] = match;
// Store the matched values into the result.
result[key] = { ...(result[key] || {}), [value]: '' };
} while ((match = regex.exec(data)) !== null) // Continue iterating until there's no more matches.
const expectedResult = locatedDfs.reduce((returnObj, current) => ({ ...returnObj, [current]: result[current] }), {});
console.log(expectedResult);
I got a result like this :
const result = [ 'arg', 'arg2', '[opt1, opt2]' ]
How can I check in this array if a string can be a array ('[opt1, opt2]') and formate it in real array ?
Thank you
EDIT :
I explain all problem :
I want create a script :
yarn start arg1 arg2 "[option1, option2]"
I need a array of options but I can have a lot args without restrictions, when I recover the result :
const res = process.argv.slice(2)
How can I find my array of options ?
You can try the following solution with string manipulation
const result = ['arg', 'arg2', "[option1, option2]"]
const output = result.map(item => {
if (/^\[.+\]$/.test(item)) {
const prepared = item
.replace('[', '["')
.replace(']', '"]')
.replace(/([a-zA-Z0-9]+),+\s+/g, '$1", "')
return JSON.parse(prepared)
}
return item
})
console.log(output)
Explanation:
/^\[.+\]$/ regex - checks whether the element is an array (based on the presence of matching square brackets)
all other replace statements change the string into valid string encoded JSON array.
Since the overall result is a valid string encoded JSON array, just use JSON.parse after that and return it.
I have project in which I need to develop a specific calculator. By far everything is good but now I am stuck in one problem. I have an array of the object containing letter as key and its value as below
valueList = [{a:5}, {b:3}, {c:8}, {d:6}]
and I have an input element where user can type specific characters like this
input = "a+b-c"
how do I modifie the above string to the new string that contains values of alphabets from valueList like
newVar = "5+3-8"
I have tried below solution with no far success
const final = input.split("").map((variable) => {
return valueList.forEach((element) => {
if (variable === Object.keys(element)[0]) {
return Object.values(element)[0];
} else {
return variable;
}
});
});
console.log(final);
First turn the valueList into an object with multiple properties, rather than an array of objects with single properties. Then use a regular expression to match any of the keys of the objects, and use a replacer function to look up the matching value on the object:
const valueList = [{a:5}, {b:3}, {c:8}, {d:6}];
const obj = Object.assign({}, ...valueList);
const input = "a+b-c";
const pattern = new RegExp(
Object.keys(obj).join('|'),
'g'
);
const output = input.replace(pattern, match => obj[match]);
console.log(output);