JS match string from right to left - javascript

Let's say I have the following object:
const obj = {
'myApi': ['keyOne', 'keyTwo'],
'myApi.keyOne': ['three', 'four'],
'myApi.keyTwo': [...],
'myApi.keyOne.three': [...]
'myApi.keyOne.four': [...]
}
Now, based on the following string:
const str = "if(myApi.keyOne.three"
I want to match the correct object key, but from right to left. So, in the above example, I want to get obj["myApi.keyOne.three"].
indexOf or str.test methods will not work because they will catch myApi and myApi.keyOne also.
Note that it could be any string, the str is just an example. For example:
while(myApi.keyOne.three) {} // should match obj["myApi.keyOne.three"]
if(myApi.keyOne) {} // should match obj["myApi.keyOne"]
etc.
How can I do this?

To get the key, use a regular expression to match myApi, followed by any number of repeated groups of (a period followed by word characters). Then, you can just access the appropriate key on the object:
const obj = {
'myApi': ['keyOne', 'keyTwo'],
'myApi.keyOne': ['three', 'four'],
'myApi.keyOne.three': ['foobar']
};
function getVal(str) {
const key = str.match(/myApi(?:\.\w+)*/)[0];
console.log(obj[key]);
return obj[key];
}
getVal("if(myApi.keyOne.three");
getVal("while(myApi.keyOne.three) {}");
getVal("if(myApi.keyOne) {}");

Search for the key entry in the pattern:
var result = “”;
Object.keys(obj).forEach(function(key) {
if (str.indexOf(key) !== -1 && key.length > result.length) result = key;
});
console.log(obj[result]);

To make things more dynamic (even if there's no guarantee about myApi):
function findStuff(str, obj) {
const keys = Object.keys(obj);
keys.sort((a, b) => b.length - a.length);
// https://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
const re = new RegExp(keys.map(key => key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).join('|'));
const match = str.match(re);
return match && match[0];
}
const obj = {
'myApi': ['keyOne', 'keyTwo'],
'myApi.keyOne': ['three', 'four'],
'myApi.keyTwo': [""],
'myApi.keyOne.three': ["THREE"],
'myApi.keyOne.four': [""]
}
console.log(findStuff('while(myApi.keyOne.three) {}', obj));
We take all the keys from the object, then sort them by descending length (so the longest will be matched first). Then regexp-escape them and stick them together in a regexp alternation.

You can use a regular expression like
myApi(\.\w+)*
Details:
myApi - matches the "myApi" string
(\.\w+)* - matches 0 or more repetitions of those alphanumeric strings which follows a period (.) character
const obj = {
'myApi': ['keyOne', 'keyTwo'],
'myApi.keyOne': ['three', 'four'],
'myApi.keyTwo': ['someVlaue1'],
'myApi.keyOne.three': ['someVlaue2'],
'myApi.keyOne.four': ['someVlaue3']
}
var str1 = 'while(myApi.keyOne.three) {}';
var str2 = 'if(myApi.keyOne) {}';
var regex = /myApi(\.\w+)*/g;
var val1 = obj[ str1.match(regex)[0] ];
var val2 = obj[ str2.match(regex)[0] ];
console.log(val1);
console.log(val2);

Related

How to filter exact words from a string?

My main objective is to check if the string contains array of words.
If the string contain $ in front of a word, I don't want it to check the string for array of words and want to straight way console.log it.
The problem I'm having is that its not checking for "Exact words".
For example if you put E, the text should show up since, there's no words that contains only 'E' however, its not showing up.
For instance:
const res = `EU, U.S. REACH DEAL TO RESOLVE BOEING-AIRBUS TRADE DISPUTE
$BA`;
const filters = ["E", "OPEC", "Repo"];
if (!filters.some(element => res.includes(element))) {
console.log(res);
}
Another method, I was thinking maybe using the split method and to check for every array item whether it's a filtered word or not.
var res = `EU, U.S. REACH DEAL TO RESOLVE BOEING-AIRBUS TRADE DISPUTE $BA`;
var filters = ["E", "OPEC", "Repo"];
if (filters.some(element => new RegExp('\\b'+element + '\\b').test(res))) {
console.log(res);
}
Use ES6 Array.filter() and arrow functions with expression body:
var words = ['get', 'help', 'set', 'moon', 'class', 'code', 'Get', ];
var letter = 'e';
var word = "get";
const output = words.filter(x=>x.includes(letter));
console.log(output);
const output2 = words.filter(x => x.toLowerCase().includes(word));
console.log(output2);
.split() each string into an array of lower cased strings (delimiter is a space or a comma). If there's more than one string to be filtered, put them into an array
const strings = ['aaa, BBB, ccc', 'vhko nuu', 'String'];
let arrArr = strings.map(str => {
return str.toLowerCase().split(/[,\s]/);
});
// arrArr = [['aaa', 'bbb', 'ccc'], ['vhko', 'nuu'], ['string']]
Then run each string array of arrArr (array of arrays) through .flatMap((strArr, idx)... and each string of each strArr (string array) through .flatMap(str...
return arrArr.flatMap((strArr, idx) => {
return strArr.flatMap(str => {...
For each str (string) use .includes(list) and .startsWith(char) in a ternary to test if str is in the list or if it starts with a specific string (if the third parameter char was passed).
<IF> list.includes(str) ? <TRUE|THEN> [strings[idx]]
: <ELSE IF> char && str.startsWith(char) ? <TRUE|THEN> [strings[idx]]
: <ELSE|THEN> [];
const strs = [
`EU, U.S. REACH DEAL TO RESOLVE BOEING-AIRBUS TRADE DISPUTE $BA`,
`a, b, C, d, E, f`,
`OPEC reaches agreement`,
`This has opec., repo#, and a dollar$ so this should be ignored`
];
const words = ["e", "opec", "repo"];
const wordFilter = (list, strings, char) => {
let arrArr = strings.map(str => {
return str.toLowerCase().split(/[,\s]/);
});
return arrArr.flatMap((strArr, idx) => {
return strArr.flatMap(str => {
return list.includes(str) ? [strings[idx]] :
char && str.startsWith(char) ? [strings[idx]] :
[];
});
});
};
console.log(wordFilter(words, strs, '$'));
I think you can get some idea from this example.click here to see jsFiddle
var words = ['get', 'help', 'set', 'moon', 'class', 'code'];
var letter = 'e';
function find(words, letter) {
letter = letter.split(''); //get it to as object the we can use it in every method as follwing
return words.filter(function(word) { //get pne buy one word in words array
return letter.every(function(char) {
return word.includes(char); // return word including the letter that you request
});
});
}
const output = find(words, letter);
console.log(output);

How can I check if a string item within an array is all uppercase?

I have an array called Symbols, it gets strings found by a regular expression pushed into it.
I now need to sort through the array and find out if there is a string that has every letter capitalized in it. I have tried similar things in the classified function below everything has returned "false" thus far, even if there is an element that is just "AAAA"
let symbols = [];
let regr = RegExp(/{\$([^\$]+)\$}/, 'g')
function genToken(inStream){
let array;
let vrtStream = inStream.trim();
console.log("Extracting meaningful symbols from string: ", vrtStream);
while((array = regr.exec(vrtStream)) !== null){
console.log(`Meaningful symbol: ${array[0]} found and assigned. Next starts at ${regr.lastIndex}.`)
symbols.push(array)
}
if(symbols.length > 0){
for(index = 0; index < symbols.length; index++){
symbols[index].splice(0, 1);
console.log(`${symbols[index].length} meaningful symbols currently indexed.`);
console.log(symbols);
}// end for
return classify(symbols);
} else {
console.log("no elements in array");
}
function classify(data, index){
console.log("Classify called", symbols)
//symbols is data
symbols.forEach(function(item, index, array){
if(item.toUpperCase == true){
console.log(`${item} is upper`)
} else {
console.log('false');
}
})
}
}
If you need to know which items in an array are all caps, you can map over them and use the regexp test method:
const arr = ['aaa', 'aAa', 'AAa', 'AAA', 'AAAa'];
const allCaps = arr.map(el => /^[A-Z]+$/.test(el));
console.log(allCaps);
If you just need to find the first one, or filter to only include the ones that match, you can use the find or filter array methods:
const arr = ['aaa', 'aAa', 'AAa', 'AAA', 'AAAa', 'BBBB'];
const first = arr.find(el => /^[A-Z]+$/.test(el));
console.log(first);
const all = arr.filter(el => /^[A-Z]+$/.test(el));
console.log(all);
Easy way to check if string is all uppercase is create uppercase string from it and then check if it is same as old string
// just some dummy data
const array = ["some data", "AAAA", "AAaA", "AAAAAB", "ALL_CAPS"];
// actual code to check if string is all uppercase
const allCapsArray = array.filter((str) => str.toUpperCase() === str);
// just printing output
console.log(allCapsArray);

Convert an array of string key pairs to an object

I have this data structure:
[
'ecl:hzl byr:1926 iyr:2010,pid:221225902 cid:61 hgt:186cm eyr:2021 hcl:#7d3b0c',
'hcl:#efcc98 hgt:178 pid:433543520,eyr:2020 byr:1926,ecl:blu cid:92,iyr:2010',
'iyr:2018,eyr:2026,byr:1946 ecl:brn,hcl:#b6652a hgt:158cm,pid:822320101'
]
I'm looking to convert those array values to objects instead of strings. I understand I need to do a map with a split(' '), but unsure of the logic inside of there.
Desired output:
[
{ecl: 'hzl', byr: 1926},
{hcl: '#efcc98', byr: 1926}
]
etc. with all of the fields.
I've tried:
.map(values => { let pair = values.split(':'); obj[pair[0]] = pair[1]; return obj })
But seem to get the same object repeated over and over, from the first index of the array.
If you're looking to get each element of the array as a separate object then try this:
const input = [
'ecl:hzl byr:1926 iyr:2010,pid:221225902 cid:61 hgt:186cm eyr:2021 hcl:#7d3b0c',
'hcl:#efcc98 hgt:178 pid:433543520,eyr:2020 byr:1926,ecl:blu cid:92,iyr:2010',
'iyr:2018,eyr:2026,byr:1946 ecl:brn,hcl:#b6652a hgt:158cm,pid:822320101'
]
const output = input.map((string) => { // for each string in array
const pairs = string.split(/[\ ,]/); // split by space or comma
const object = {}; // create an object
for (pair of pairs) { // for each pair in string
const parts = pair.split(":"); // split by colon
if (parts.length == 2) { // if you get 2 parts after splitting
object[parts[0]] = parts[1]; // use the first part as a key and the second as a value
}
}
return object;
});
console.log(output);
Try this
array = array.map(val => {
var obj = {}
val.split(' ').forEach(keyValPair => {
var keyVal = keyValPair.split(':')
obj[keyVal[0]] = keyVal[1];
})
return obj;
})
You can use Object.fromEntries.
const arr = [
'ecl:hzl byr:1926 iyr:2010,pid:221225902 cid:61 hgt:186cm eyr:2021 hcl:#7d3b0c',
'hcl:#efcc98 hgt:178 pid:433543520,eyr:2020 byr:1926,ecl:blu cid:92,iyr:2010',
'iyr:2018,eyr:2026,byr:1946 ecl:brn,hcl:#b6652a hgt:158cm,pid:822320101'
];
const res = arr.map(x => Object.fromEntries(x.replace(/,/g, ' ')
.split(' ').map(y => y.split(':'))));
console.log(res);

Can I use wildcards when searching an array of strings in Javascript?

Given an array of strings:
x = ["banana","apple","orange"]
is there a built in shortcut for performing wildcard searches?
ie., maybe
x.indexOf("*na*") //returns index of a string containing the substring na
Expanding on Pim's answer, the correct way to do it (without jQuery) would be this:
Array.prototype.find = function(match) {
return this.filter(function(item){
return typeof item == 'string' && item.indexOf(match) > -1;
});
}
But really, unless you're using this functionality in multiple places, you can just use the existing filter method:
var result = x.filter(function(item){
return typeof item == 'string' && item.indexOf("na") > -1;
});
The RegExp version is similar, but I think it will create a little bit more overhead:
Array.prototype.findReg = function(match) {
var reg = new RegExp(match);
return this.filter(function(item){
return typeof item == 'string' && item.match(reg);
});
}
It does provide the flexibility to allow you to specify a valid RegExp string, though.
x.findReg('a'); // returns all three
x.findReg("a$"); // returns only "banana" since it's looking for 'a' at the end of the string.
Extending on #Shmiddty's answer, here are useful JavaScript ideas:
Extend Array with a new method: Array.prototype.method = function(arg) { return result; }
Filter arrays using: Array.filter(function(e) { return true|false; })
Apply formula to elements in an array: Array.map(function(e) { return formula(e); })
Use regular expressions: either /.*na.*/ or new Regex('.*na.*')
Use regular expressions to match: let result = regex.test(input);
Use Array.prototype.reduce to aggergate a result after running a function on every element of an array
i.e. I prefer the input argument to be a regex, so, it gives you either:
A short but universal pattern matching input,
e.g. contains, starts with, ends width, as well as more sophisticated matches
The ability to specify an input pattern as a string
SOLUTION 1: filter, test, map and indexOf
Array.prototype.find = function(regex) {
const arr = this;
const matches = arr.filter( function(e) { return regex.test(e); } );
return matches.map(function(e) { return arr.indexOf(e); } );
};
let x = [ "banana", "apple", "orange" ];
console.log(x.find(/na/)); // Contains 'na'? Outputs: [0]
console.log(x.find(/a/)); // Contains 'a'? Outputs: [0,1,2]
console.log(x.find(/^a/)); // Starts with 'a'? Outputs: [1]
console.log(x.find(/e$/)); // Ends with 'e'? Outputs: [1,2]
console.log(x.find(/pear/)); // Contains 'pear'? Outputs: []
SOLUTION 2: reduce, test
Array.prototype.find = function(regex) {
return this.reduce(function (acc, curr, index, arr) {
if (regex.test(curr)) { acc.push(index); }
return acc;
}, [ ]);
}
let x = [ "banana", "apple", "orange" ];
console.log(x.find(/na/)); // Contains 'na'? Outputs: [0]
console.log(x.find(/a/)); // Contains 'a'? Outputs: [0,1,2]
console.log(x.find(/^a/)); // Starts with 'a'? Outputs: [1]
console.log(x.find(/e$/)); // Ends with 'e'? Outputs: [1,2]
console.log(x.find(/pear/)); // Contains 'pear'? Outputs: []
You can extend the array prototype to find matches in an array
Array.prototype.find = function(match) {
var matches = [];
$.each(this, function(index, str) {
if(str.indexOf(match) !== -1) {
matches.push(index);
}
});
return matches;
}
You can then call find on your array like so
// returns [0,3]
["banana","apple","orange", "testna"].find('na');
using regex can do this in javascript
var searchin = item.toLowerCase();
var str = columnId;
str = str.replace(/[*]/g, ".*").toLowerCase().trim();
return new RegExp("^"+ str + "$").test(searchin);
In addition to everything else that has been said, you can do this:
var x = ["banana", "apple", "orange"];
var y = [];
for (var i in x) {
if (x[i].indexOf('na') > -1) {
y.push(i);
}
}
Results: y = [0]

Regex to split string into separate keys

Working on a bit of an interesting project and I'm having a little trouble writing regex for this.
Using regex and Javascript, I want to split my input string into an array of "keys". Strings that have an invalid key should return 0 keys (null, empty array, whatever is fine).
The "spec"
<input string> => <matches>
# named keys
a => ['a']
b => ['b']
foo[bar] => ['foo', 'bar']
# numeric keys are ok too
a[0] => ['a', '0']
b[1] => ['b', '1']
# 'push' syntax is also valid
push[] => ['push', '']
hello[] => ['hello', '']
# complex!
complex[named][0][] => ['complex', 'named', '0', '']
Invalid examples
# named keys must start with [a-zA-Z]
_invalid => null
3foo[abc] => null
# named keys can include a number as long as they start with a letter
foo3valid[this_is_valid_2] => ['foo3valid', 'this_is_valid_2']
What I have so far
var regex = /^(?:\[?([a-zA-Z][a-zA-Z0-9_]*|[a-zA-Z0-9_]*)\]?)+$/g;
var keys = [];
myInput.replace(regex, function(match,capture,pos,source){
keys.push(capture);
});
console.log(myInput, keys);
How it fails
My regex is matching only the last "key" E.g.,
# should be ['a', 'b', 'c']
a[b][c] => ['c']
Tinker on jsFiddle
jsfiddle
I have taken another approach to get the desired results:
Test whether the given phrase is valid.
If valid, use a global match to create an array.
Code: Fiddle: http://jsfiddle.net/MVJZc/2/
///Example
var myInput = "a[b][][c]";
var validate = /^[a-zA-Z][a-zA-Z0-9_]*(?:\[(?:\d*|[a-zA-Z0-9_]+)\])*$/,
pattern = /[a-zA-Z0-9_]+|(?=\[\])/g,
//(?=\[\]) is used to create an empty entry for []
keys = null;
if (validate.test(myInput)) {
keys = myInput.match(pattern);
}
Note: If you want to extend the pattern, e.g. to include the $ character, modify the first RegEx. The second RegEx (pattern) should at least contain all valid characters.
would something like this work?
var input = "a[b][c]";
input = input.replace(/[\[\]]$/,"").replace(/[\]\[]+/g,"|");
var args = input.split("|");
And here's a demo:
http://jsfiddle.net/vZBtj/
Here's another possibility, definitely not as succinct as Rob W's, but get's the job done ;-)
function parseThing(aStr){
var res = [];
success = false;
if(aStr.indexOf('[') > 0){
var idx = aStr.indexOf('[');
var first = aStr.substring(0, idx);
if(first.match(/\w/)){
success = true;
res.push(first);
//now parse stuff inside brackets
var rest = aStr.substring(idx, aStr.length-1);
var arr = rest.split("]");
for(i in arr){
res.push(arr[i].replace("[", ""));
}
}
} else if(aStr.match(/\w/)){
res.push(aStr);
}
return res;
}
console.log(parseThing("a[a][b]"));
console.log(parseThing("a"));
console.log(parseThing("b"));
console.log(parseThing("foo[bar] "));
console.log(parseThing("a[0]"));
console.log(parseThing("b[1]"));
console.log(parseThing("complex[named][0][]"));

Categories

Resources