I have a string like "this/ is an example abc/def/fgh/uio to give you an example"
I'd like to target the longest word and replace on this substring any "/" by a "+".
I manage to identify the longest word and I would know how to replace ALL "/" by a "+" BUT I don't know how to replace the "/" only in the longest word.
Here's what I've got so far
//identify longest word in string
function longestWord(str) {
var words = str.split(' ');
return words.reduce(longer);
}
function longer(champ, contender) {
return (contender.length > champ.length) ? contender: champ;
}
//purely given an exemple, some strigns won't be exactly like this
var text2 = "this/ is an example abc/def/fgh/uio to give you an example"
if (longestWord(text2) > 30 ) {
text2.replace(/\//g, ' / ');
}
The problem is this will also replace the "/" on the substring "this/", and I don't want that.
How to achieve this?
Your longestWord function returns the longest word in the string, so you can pass that string alone (not a regular expression) as the first argument to .replace, and replace with (the second argument) the /\//g called on that longest word:
function getLongestWord(str) {
var words = str.split(' ');
return words.reduce(longer);
}
function longer(champ, contender) {
return (contender.length > champ.length) ? contender: champ;
}
var text2 = "this/ is an example abc/def/fgh/uio to give you an example"
const longestWord = getLongestWord(text2);
const output = text2.replace(longestWord, longestWord.replace(/\//g, '+'));
console.log(output);
#CertainPermance's solution is far more elegant (and I think performant) than this, but as I'd written the answer I thought I may as well put it in.
It's fairly similar, in truth, though in this instance we get the index of the word and use that to perform the replace, which at the time of writing I thought was necessary. Now looking at the better solution, I realise such a check is not needed, as the longest word in a string will not feature in any other words, so it's easy and safe to simply perform a replace on it.
const data = "this/ is an example abc/def/fgh/uio to give you an example";
const getLongestWordIndex = stringIn => stringIn
.split(' ')
.reduce(
(prev, curr, i) => curr.length > prev.length ? {
index: i,
length: curr.length
} : prev,
{
length: -1,
index: -1
}
).index
const replaceLongestWord = (sentence, replacer) => {
const longestWordIndex = getLongestWordIndex(sentence);
const words = data.split(' ');
return Object.values({
...words,
[longestWordIndex]: replacer(words[longestWordIndex])
}).join(' ')
}
const wordReplaceFunction = word => word.replace(/\//g, '+')
const result = replaceLongestWord(data, wordReplaceFunction);
console.dir(result)
Related
I want to change to make the first letters of the words in the string uppercase, and after translating into an array, I use the map method. The problem is that inheritance does not work in this method, as I understand it, because when you return the map element, the original string is returned:
const str = 'dkdg gkdj wijoerbj'
let r = str.split(' ').map((item, index) => {
item[0] = item[0].toUpperCase()
return item
})
unchanged first letters will also be returned with such a code entry(is in the map()):
item[0] = item[0].toUpperCase()
return item[0]
however, when I return the first line, the letters still become uppercase, but I do not know how to return the rest of the word in this case(is in the map()):
return item[0] = item[0].toUpperCase()
why inheritance does not work as it should, tell me, please, and how to add the rest of the word if there are no other options?
You need to cancat the first letter with rest of the string. Also these two lines item[0] = item[0].toUpperCase();return item though will convert the first letter to uppercase but it will still return the original sting because item represent the original word nut not the modified text
const str = 'dkdg gkdj wijoerbj'
let r = str.split(' ').map((item, index) => {
return item.charAt(0).toUpperCase() + item.substring(1, item.length)
});
console.log(r)
We can do this with two array map methods as bellow.
const str = 'dkdg gkdj wijoerbj';
let r = str.split(' ').map((item, index) => {
return ([...item].map((letter, i) => {
return (i == 0) ? letter.toUpperCase() : letter;
})).join('');
});
console.log(r);
const str = 'dkdg gkdj wijoerbj'
let r = str.split(' ').map(x=> x[0].toLocaleUpperCase());
console.log(r)
u can try this code to get first letters of the words in the string uppercase into new arry using map and returns capital letter of each first letter
Let's consider a string str which is defined as :
const str = " 'I am going' - 'I' "
and a function calc() which can be used as :
console.log( calc(str) ) // => am going
So, I decided to make the calc() using regex ! So here is what I thought about.
const calc = (str) => {
const reg = // Not understanding how to get the strings between which '-' falls
str = str.replace(reg, function(_, a) {
const b = remove(a[0], a[1])
return b
})
return str
}
remove() is a function for removing words from string, I made. You can freely modify my code if there is anything incorrect. It's an example how I imagined. So, please help me completing my function !
You could split the string at - and get the content within '' suing match. Then, create a dynamic regex using the RegExp constructor and replace all the instance of second match from the first match
function calc(str) {
const [first, second] = str.split(/\s*-\s*/)
.map(s => s.match(/'([^']+)'/)[1])
return first.replace(new RegExp(second, "g"), '')
}
console.log(calc("'I am going' - 'I'"))
console.log(calc("'Remove this from this string' - 'this'"))
If matchAll is supported in your environment, you could also:
const [first, second] = Array.from(str.matchAll(/'([^']+)'/g), ([,m]) => m)
The emphasis here is on the word exactly. This needs to work for any number of permutations, so hopefully my example is clear enough.
Given a string of random letters, is it possible (using RegEx) to match an exact number of letters within the given string?
So if I have a string (str1) containing letters ABZBABJDCDAZ and I wanted to match the letters JDBBAA (str2), my function should return true because str1 contains all the right letters enough times. If however str1 were to be changed to ABAJDCDA, then the function would return false as str2 requires that str1 have at least 2 instances of the letter B.
This is what I have so far using a range:
const findLetters = (str1, str2) => {
const regex = new RegExp(`[${str2}]`, 'g')
const result = (str1.match(regex))
console.log(result)
}
findLetters('ABZBABJDCDAZ', 'JDBBAA')
As you can see it matches the right letters, but it matches all instances of them. Is there any way to do what I'm trying to do using RegEx? The reason I'm focusing on RegEx here is because I need this code to be highly optimised, and so far my other functions using Array.every() and indexOf() are just too slow.
Note: My function only requires to return a true/false value.
Try (here we sort letters of both strings and then create regexp like A.*A.*B.*B.*D.*J)
const findLetters = (str1, str2) => {
const regex = new RegExp([...str2].sort().join`.*`)
return regex.test([...str1].sort().join``)
}
console.log( findLetters('ABZBABJDCDAZ', 'JDBBAA') );
console.log( findLetters('ABAJDCDA', 'JDBBAA') );
I dont know if regex is the right way for this as this can also get very expensive. Regex is fast, but not always the fastest.
const findLetters2 = (strSearchIn, strSearchFor) => {
var strSearchInSorted = strSearchIn.split('').sort(function(a, b) {
return a.localeCompare(b);
});
var strSearchForSorted = strSearchFor.split('').sort(function(a, b) {
return a.localeCompare(b);
});
return hasAllChars(strSearchInSorted, strSearchForSorted);
}
const hasAllChars = (searchInCharList, searchCharList) => {
var counter = 0;
for (i = 0; i < searchCharList.length; i++) {
var found = false;
for (counter; counter < searchInCharList.length;) {
counter++;
if (searchCharList[i] == searchInCharList[counter - 1]) {
found = true;
break;
}
}
if (found == false) return false;
}
return true;
}
// No-Regex solution
console.log('true: ' + findLetters2('abcABC', 'abcABC'));
console.log('true: ' + findLetters2('abcABC', 'acbACB'));
console.log('true: ' + findLetters2('abcABCx', 'acbACB'));
console.log('false: ' + findLetters2('abcABC', 'acbACBx'));
console.log('true: ' + findLetters2('ahfffmbbbertwcAtzrBCasdf', 'acbACB'));
console.log('false: ' + findLetters2('abcABC', 'acbAACB'));
Feel free to test it's speed and to optimize it as I'm no js expert. This solution should iterate each string once after sorting. Sorting is thanks to https://stackoverflow.com/a/51169/9338645.
I have a string which is composed of terms separated by slashes ('/'), for example:
ab/c/def
I want to find all the prefixes of this string up to an occurrence of a slash or end of string, i.e. for the above example I expect to get:
ab
ab/c
ab/c/def
I've tried a regex like this: /^(.*)[\/$]/, but it returns a single match - ab/c/ with the parenthesized result ab/c, accordingly.
EDIT :
I know this can be done quite easily using split, I am looking specifically for a solution using RegExp.
NO, you can't do that with a pure regex.
Why? Because you need substrings starting at one and the same location in the string, while regex matches non-overlapping chunks of text and then advances its index to search for another match.
OK, what about capturing groups? They are only helpful if you know how many /-separated chunks you have in the input string. You could then use
var s = 'ab/c/def'; // There are exact 3 parts
console.log(/^(([^\/]+)\/[^\/]+)\/[^\/]+$/.exec(s));
// => [ "ab/c/def", "ab/c", "ab" ]
However, it is unlikely you know that many details about your input string.
You may use the following code rather than a regex:
var s = 'ab/c/def';
var chunks = s.split('/');
var res = [];
for(var i=0;i<chunks.length;i++) {
res.length > 0 ? res.push(chunks.slice(0,i).join('/')+'/'+chunks[i]) : res.push(chunks[i]);
}
console.log(res);
First, you can split the string with /. Then, iterate through the elements and build the res array.
I do not think a regular expression is what you are after. A simple split and loop over the array can give you the result.
var str = "ab/c/def";
var result = str.split("/").reduce(function(a,s,i){
var last = a[i-1] ? a[i-1] + "/" : "";
a.push(last + s);
return a;
}, []);
console.log(result);
or another way
var str = "ab/c/def",
result = [],
parts=str.split("/");
while(parts.length){
console.log(parts);
result.unshift(parts.join("/"));
parts.pop();
}
console.log(result);
Plenty of other ways to do it.
You can't do it with a RegEx in javascript but you can split parts and join them respectively together:
var array = "ab/c/def".split('/'), newArray = [], key = 0;
while (value = array[key++]) {
newArray.push(key == 1 ? value : newArray[newArray.length - 1] + "/" + value)
}
console.log(newArray);
May be like this
var str = "ab/c/def",
result = str.match(/.+?(?=\/|$)/g)
.map((e,i,a) => a[i-1] ? a[i] = a[i-1] + e : e);
console.log(result);
Couldn't you just split the string on the separator character?
var result = 'ab/c/def'.split(/\//g);
What is the best way to bold a part of string in Javascript?
I have an array of objects. Each object has a name. There is also an input parameter.
If, for example, you write "sa" in input, it automatically searches in array looking for objects with names that contain "sa" string.
When I print all the names, I want to bold the part of the name that coincide with the input text.
For example, if I search for "Ma":
Maria
Amaria
etc...
I need a solution that doesn't use jQuery. Help is appreciated.
PD: The final strings are in the tag. I create a list using angular ng-repeat.
This is the code:
$scope.users = data;
for (var i = data.length - 1; i >= 0; i--) {
data[i].name=data[i].name.replace($scope.modelCiudad,"<b>"+$scope.modelCiudad+"</b>");
};
ModelCiudad is the input text content var. And data is the array of objects.
In this code if for example ModelCiudad is "ma" the result of each is:
<b>Ma</b>ria
not Maria
You can use Javascript's str.replace() method, where str is equal to all of the text you want to search through.
var str = "Hello";
var substr = "el";
str.replace(substr, '<b>' + substr + '</b>');
The above will only replace the first instance of substr. If you want to handle replacing multiple substrings within a string, you have to use a regular expression with the g modifier.
function boldString(str, substr) {
var strRegExp = new RegExp(substr, 'g');
return str.replace(strRegExp, '<b>'+substr+'</b>');
}
In practice calling boldString would looks something like:
boldString("Hello, can you help me?", "el");
// Returns: H<b>el</b>lo can you h<b>el</b>p me?
Which when rendered by the browser will look something like: Hello can you help me?
Here is a JSFiddle with an example: https://jsfiddle.net/1rennp8r/3/
A concise ES6 solution could look something like this:
const boldString = (str, substr) => str.replace(RegExp(substr, 'g'), `<b>${substr}</b>`);
Where str is the string you want to modify, and substr is the substring to bold.
ES12 introduces a new string method str.replaceAll() which obviates the need for regex if replacing all occurrences at once. It's usage in this case would look something like this:
const boldString = (str, substr) => str.replaceAll(substr, `<b>${substr}</b>`);
I should mention that in order for these latter approaches to work, your environment must support ES6/ES12 (or use a tool like Babel to transpile).
Another important note is that all of these approaches are case sensitive.
Here's a pure JS solution that preserves the original case (ignoring the case of the query thus):
const boldQuery = (str, query) => {
const n = str.toUpperCase();
const q = query.toUpperCase();
const x = n.indexOf(q);
if (!q || x === -1) {
return str; // bail early
}
const l = q.length;
return str.substr(0, x) + '<b>' + str.substr(x, l) + '</b>' + str.substr(x + l);
}
Test:
boldQuery('Maria', 'mar'); // "<b>Mar</b>ia"
boldQuery('Almaria', 'Mar'); // "Al<b>mar</b>ia"
I ran into a similar problem today - except I wanted to match whole words and not substrings. so if const text = 'The quick brown foxes jumped' and const word = 'foxes' than I want the result to be 'The quick brown <strong>foxes</strong> jumped'; however if const word = 'fox', than I expect no change.
I ended up doing something similar to the following:
const pattern = `(\\s|\\b)(${word})(\\s|\\b)`;
const regexp = new RegExp(pattern, 'ig'); // ignore case (optional) and match all
const replaceMask = `$1<strong>$2</strong>$3`;
return text.replace(regexp, replaceMask);
First I get the exact word which is either before/after some whitespace or a word boundary, and then I replace it with the same whitespace (if any) and word, except the word is wrapped in a <strong> tag.
Here is a version I came up with if you want to style words or individual characters at their index in react/javascript.
replaceAt( yourArrayOfIndexes, yourString/orArrayOfStrings )
Working example: https://codesandbox.io/s/ov7zxp9mjq
function replaceAt(indexArray, [...string]) {
const replaceValue = i => string[i] = <b>{string[i]}</b>;
indexArray.forEach(replaceValue);
return string;
}
And here is another alternate method
function replaceAt(indexArray, [...string]) {
const startTag = '<b>';
const endTag = '</b>';
const tagLetter = i => string.splice(i, 1, startTag + string[i] + endTag);
indexArray.forEach(tagLetter);
return string.join('');
}
And another...
function replaceAt(indexArray, [...string]) {
for (let i = 0; i < indexArray.length; i++) {
string = Object.assign(string, {
[indexArray[i]]: <b>{string[indexArray[i]]}</b>
});
}
return string;
}
Above solutions are great, but are limited! Imagine a test scenerio where you want to match case insensitive query in a string and they could be multiple matches.
For example
Query: ma
String: The Amazing Spiderman
Expected Result: The Amazing Spiderman
For above scenerio, use this:
const boldMatchText = (text,searchInput) => {
let str = text.toLowerCase();
const query = searchInput.toLowerCase();
let result = "";
let queryLoc = str.indexOf(query);
if (queryLoc === -1) {
result += text;
} else
do {
result += ` ${text.substr(0, queryLoc)}
<b>${text.substr(queryLoc, query.length)}</b>`;
str = str.substr(queryLoc + query.length, str.length);
text = text.substr(queryLoc + query.length, str.length);
queryLoc = str.indexOf(query);
} while (text.length > 0 && queryLoc !== -1);
return result + text;
};