I have an input field where users can search a database for a certain name. The database contains names such as "Doe, John".
If a user searches for "john" I think it's easy to implement. However, if he or she searches for "john Doe" I would like to implement the logic search for john or search for doe.
With RegEx I am completely lost. Is something like this even possible? However, with JS I would at least be able to consider this algorithm:
Split the input on a whitespace and create to arrays
Remove special characters
Filter the JSON object retrieved from the database
check, whether item includes the cleansed string-arrays
As for the JS-functions I tried something (in vain):
let search = 'John Doe' //user input
let data = ['Doe, John', 'Bean, Mister'] //data from database
let split = search.split(" ") //split the whitespace into two arrays
split = split.map(item => { return item.replace(/[^\w\s]+/gi, '')}) //remove dots, commas etc.
let result = data.filter(item => { //filter each item from the data...
split.forEach(element => {
let found = item.match(new RegExp(element, "i")) // so here I get matches, but how can I move them up the let the filter method return true?
return found.length
}).length>0
})
console.log(result)
Thanks to Taplars comment, I have used a map-method instead of a forEach:
let data = ['Doe, John', 'Bean, Mister']
let split = search.split(" ")
split = split.map(item => { return item.replace(/[^\w\s]+/gi, '')})
let result = data.filter(item => {
let filtered = split.map(element => {
let ret = item.match(new RegExp(element, "i"))
return ret
})
console.log(item,filtered) //now I have two arrays, one with something meaningful and one with [null,null]. How can I remove empty arrays?
return filtered.length>0
})
console.log(result)
Try the following:
Get the search expression and turn it into a series of regular expressions
Iterate through the data and check to see if some or all the expressions match
const data = ['Doe, John', 'Doe, Jane', 'Smith, John', 'Bean, Mister'] // data from database
function searchEvery(input) {
const wordExpressions = input.split(/[^\w]+/g)
.filter(word => word) // remove empty entries
.map(word => new RegExp(word, 'i')); // convert to regular expression
return data.filter(item => wordExpressions.every(exp => exp.test(item)));
}
function searchSome(input) {
const wordExpressions = input.split(/[^\w]+/g)
.filter(word => word) // remove empty entries
.map(word => new RegExp(word, 'i')); // convert to regular expression
return data.filter(item => wordExpressions.some(exp => exp.test(item)));
}
console.log(searchEvery('John Doe'))
console.log(searchEvery('John'))
console.log(searchEvery('Doe'))
console.log(searchSome('John Doe'))
If you want to make it non-greedy (every user word is optional)
const data = ['Doe, John', 'Bean, Mister', 'Mardoe, Ann']; // data
const search = ' joh doe '; // user input
// Remove spaces and create Piped | options
const searchPipe = search.trim().replace(/[|\s]+/g, '|');
const result = data.filter(item => new RegExp(searchPipe, 'i').test(item));
console.log(result)
To make it greedy (must contain every word)
const data = ['Doe, John', 'Bean, Mister', 'Mardoe, Ann']; // data
const search = ' joh doe '; // user input
// Remove extra spaces and create array
const searchArr = search.trim().replace(/\s+/g, ' ').split(' ');
const result = data.filter(item => searchArr.every(sa => new RegExp(sa, 'i').test(item)));
console.log(result)
Notice, if a person named "Doe, Doe" was in the list, the above would account it (since the length) for a "john doe" search, but I think it's fine.
Related
I have a string with words followed by a colon. I need to replace the colon words in that string with values from an object. I was able to extract out the colon words but not sure on the best way to replace it in the string.
This is what I have:
const string = 'This is :state :buttonName by :name';
const buttonName = 'button link';
const data = {
state: 'Alabama',
name: 'Arun'
}
const res = string.match(/:[a-zA-Z]+/g).map(i => i.replace(':', ''))
console.log(res)
// This is Alabama button link by Arun
End result should be
This is Alabama button link by Arun
Please advice.
First of all, you need to move const buttonName = 'button link'; to the array.
You need to use String#replace, but also you need to capture the part of the regex after : and actually use the Group #1 value as key to get the right data value.
Besides, you need to check if the extracted key is inside the dictionary to avoid issues.
You can use
const string = 'This is :state :buttonName by :name';
const data = {
buttonName: 'button link',
state: 'Alabama',
name: 'Arun'
}
const res = string.replace(/:([a-zA-Z]+)/g, (m, i) => i in data ? data[i] : m)
console.log(res)
You can split the string and then call array map to replace words and the join to final string
const str= 'This is :state :buttonName by :name';
str.split(' ').map(a => {
if(a.startsWith(":"))
return data[a.replace(":","")];
return a;
}).join(' ');
If you've already stripped the ":" from the string you can just iterate your object keys and replace them with the respective values.
...
const res = string.match(/:[a-zA-Z]+/g).map(i => i.replace(':', ''))
for (const [key, value] of Object.entries(data)) {
res = res.replaceAll(key, value);
}
Wiktor's answer is good. But if it needs to replace the global variable as well, we can write the code as belows.
const res = string.replace(/:([a-zA-Z_]+)/g, (m, i) => data[i] ?? eval(i) ?? m);
console.log(res)
This code didn't do exception handling yet. It should be in consideration. So we can define a replacer function handling exception
const replacer = (m, i) => {
try {
return data[i] ?? eval(i);
} catch {
return m;
}
}
const res = string.replace(/:([a-zA-Z_]+)/g, replacer);
I have a paragraph stored in a variable named story.
story = story text;
(example).
The first step in the project is to separate each word in the story variable and store it in an array named storyWords.
Easy enough, check.
Now it wants us to iterate through storyWords, filter out unnecessaryWords and store the new array in a variable named betterWords.
unnecessaryWords = ['extremely', 'literally', 'actually'];
Here is my code:
const betterWords = storyWords.filter(word => {
if(word !== unnecessaryWords)
return word;
});
What leads me to believe that this should work is based on this code:
const betterWords = storyWords.filter(word => {
if(word !== 'extremely')
if(word !== 'literally')
if(word !== 'actually')
return word;
})
What am I not understanding here?
If you want to exclude the entry as long as it matches any of the unnecessary words that is an array:
const unnecessaryWords = ['extremely', 'literally', 'actually'];
...then you can simply return !unnecessaryWords.includes(word), which means "if word is not included in the array of unnecessaryWords, we want to keep it":
const betterWords = storyWords.filter(word => !unnecessaryWords.includes(word));
Array.prototype.includes will return true when word matches any of the array members in unnecessaryWords.
Proof-of-concept:
const unnecessaryWords = ['extremely', 'literally', 'actually'];
const storyWords = ['Lorem', 'ipsum', 'extremely', 'dolor', 'sit', 'actually', 'amet'];
const betterWords = storyWords.filter(word => !unnecessaryWords.includes(word));
console.log(betterWords);
The following uses a regular expression and String#matchAll to match word character sequences following a word boundary. Array#filter is then used to filter out the unnecessary words.
const unnecessaryWords = ['extremely', 'literally', 'actually']
function betterWords(text) {
const words = [...text.matchAll(/\b\w+/gu)].flat()
return words.filter((w) => !unnecessaryWords.includes(w))
}
const text = 'literally the story text'
console.log(betterWords(text))
You could try two approaches. Using a Array.forEach() and Array.filter() like i demonstrated below.
// Just for Illustration, let's initialize a list representing storyWords
var storyWords = ['story','extremely', 'global','actually', 'javascript','c-sharp','literally'];
var unnecessaryWords = ['extremely', 'literally', 'actually'];
//First using simple loop
var betterWordsLooped = [];
storyWords.forEach((word)=>
{
if(!unnecessaryWords.includes(word))
{
betterWordsLooped.push(word);
}
});
console.log(betterWordsLooped);
//Secondly Using Filter
var betterWordsFiltered = storyWords.filter((word)=> !unnecessaryWords.includes(word));
console.log(betterWordsFiltered);
On this code:
!unnecessaryWords.includes(word))
we want to check if the value of variable word matches any of the items contained in the string array unnecessaryWords. Remember the pattern for using Array.propotype.includes() is someArray.includes(someVar) where someArray is a [] and someVar is a string variable whose value you want to match within someArray.
I have a snippet of code where I am trying to parse a longer string with special characters into an array with no spaces or special characters.
input: name: this is some stuff, name2: this is more stuff
desired output: [name,this is some stuff,name2,this is more stuff]
current output: z.trim isn't a function
function parseOrder(custOrder) {
const custOrderArr = custOrder.split(',');
const trimedArr = custOrderArr.map((x) => x.trim());
const numberArr = trimedArr.map((y) => y.split(':'));
const processArr = numberArr.map((z) => z.trim());
console.log(processArr);
}
Why does trim work the first time and not the second?
You can not trim an array. But you could map the array and trim the values.
This result features Array#flatMap for preventing arrays with pairs.
function parseOrder(custOrder) {
return custOrder
.split(',')
.flatMap(y => y.split(':').map(x => x.trim()));
}
var input = 'name: this is some stuff, name2: this is more stuff ';
console.log(parseOrder(input));
Try to split by two signs, then trim your elements:
const result = str.split(/[\:,]+/).map(s => s.trim());
An example:
let str = 'test: It is me, test2: it is me 2 ';
console.log(str.split(/[\:,]+/).map(s => s.trim()));
How to change NoOfSAP => No Of SAP? I have trying the replace method but it says undefined.
function unCamlelCase(result) {
return result.key.replace(/([^A-Z]*)([A-Z]*)([A-Z])([^A-Z]*)/g, '$1 $2 $3$4')
.replace(/ +/g, ' ');
};
How can I change the result key values camel case to normal string?
if (exactMatch) {
const { ...response } = json[0];
const result = Object.keys(response).reduce((acc, key) => {let newKey = key.charAt(0).toUpperCase() + key.slice(1);
return acc;
}, {});
You could use the following expression with a few helper methods to clean up the output:
"NoOfSAP".split(/([A-Z][a-z]+)/).filter(Boolean).join(' ');
This will match all upper case letters followed by one or more lower-case letters and split each chunk into an array. .filter(Boolean) is then used to remove any empty strings in the array and .join is then used to add spaces between the strings in the array.
See example below:
const getWords = wrd =>
wrd.split(/([A-Z][a-z]+)/).filter(Boolean).join(' ');
console.log(getWords("NoOfSAP")); // No Of SAP
console.log(getWords("ThisIsAWord")); // This Is A Word (notice how it will split individual letters such as A)
console.log(getWords("IAmAHuman")); // I Am A Human
console.log(getWords("JSIsGreat")); // JS Is Great (notice how it understands JS and Is are two seperate words and doesn't give JSI s Great)
As per your question about changing the keys in your object to the "uncamelcased" keys you can use .map with Object.keys to generate your result:
const getWords = wrd =>
wrd.split(/([A-Z][a-z]+)/).filter(Boolean).join(' ');
const obj = {
"NoOfSAP": 1,
"NoOfBUN": 2,
"NoOfBRE": 3,
"NoOfPEA": 4
}
const result = Object.keys(obj).map(getWords);
console.log(result);
You can go that way:
const camelToWords = (camelCaseWord) => camelCaseWord
.replace(/([A-Z]+)/g, " $1")
.replace(/([A-Z][a-z])/g, "$1");
There is also possibility to use existing libraries like lodash:
const _ = require('lodash');
console.log(_.startCase('abcDef'));
// result: Abc Def
I have an array of strings.
I want to search in that array for and string that contains a specific string.
If it's found, return that string WITHOUT the bit of the string we looked for.
So, the array has three words. "Strawbery", "Lime", "Word:Word Word"
I want to search in that array and find the full string that has "Word:" in it and return "Word Word"
So far I've tried several different solutions to no avail. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes looks promising, but I'm lost. Any suggestions?
Here's what I've been trying so far:
var arrayName = ['Strawberry', 'Lime', 'Word: Word Word']
function arrayContains('Word:', arrayName) {
return (arrayName.indexOf('Word:') > -1);
}
You can use find to search the array. And use replace to remove the word.
This code will return the value of the first element only.
let arr = ["Strawbery", "Lime", "Word:Word Word"];
let search = "Word:";
let result = (arr.find(e => e.includes(search)) || "").replace(search, '');
console.log(result);
If there are multiple search results, you can use filter and map
let arr = ["Strawbery", "Word:Lime", "Word:Word Word"];
let search = "Word:";
let result = arr.filter(e => e.includes(search)).map(e => e.replace(search, ''));
console.log( result );
Use .map:
words_array = ["Strawbery", "Lime", "Word:Word Word"]
function get_word(words_array, search_word) {
res = '';
words_array.map(function(word) {
if(word.includes(search_word)) {
res = word.replace(search_word, '')
}
})
return(res)
}
Usage:
res = get_word(words_array, 'Word:')
alert(res) // returns "Word Word"