Invalid left-hand side in assignment expression - javascript

New person here working on a toy problem building a function that converts a string to camelcase anywhere there is a dash or an underscore. I have almost everything worked out except the second to last line of the function where I am trying to change the characters at each index (from my index array) to uppercase before I return the string. The error I am getting is bad assignment from the left side, but I'm not sure why. I've console logged both sides of the assignment and they seem to be doing what I want, but the assignment itself isn't working. Thank you for any help!
Here is the code:
function toCamelCase(str){
var stringArray = str.split('');
var indexArray = [];
stringArray.forEach(character => {
if (character === '-' || character === '_') {
var index = str.indexOf(character);
str = str.slice(0, index) + str.slice(index+1)
indexArray.push(index);
}
return character;
})
indexArray.forEach(index => {stringArray.splice(index, 1)});
string = stringArray.join('');
indexArray.forEach(index => {string.charAt(index) = string.charAt(index).toUpperCase()});
return string;
}

The problem is with using string.charAt() on the left hand side. That is not possible as you're trying to assign something to the result of a function, all in the same call. Store the value of string.charAt() in an intermediary variable and it should work. Check the code below for a working example, using a slightly different approach:
function toCamelCase(str){
var stringArray = str.split('');
var indexArray = [];
stringArray.forEach(character => {
if (character === '-' || character === '_') {
var index = str.indexOf(character);
str = str.slice(0, index) + str.slice(index+1)
indexArray.push(index);
}
return character;
});
indexArray.forEach(index => {stringArray.splice(index, 1)});
return stringArray.map((char, index) => {
return indexArray.includes(index) ? char.toUpperCase() : char;
}).join('');
}

Ah thank you both for pointing me in the right direction. Instead of joining it back to a string I took advantage of it being an array already and just looped through that first.
This code worked...
function toCamelCase(str){
var stringArray = str.split('');
var indexArray = [];
stringArray.forEach(character => {
if (character === '-' || character === '_') {
var index = str.indexOf(character);
str = str.slice(0, index) + str.slice(index+1)
indexArray.push(index);
}
return character;
})
indexArray.forEach(index => {stringArray.splice(index, 1)});
indexArray.forEach(index => {stringArray[index] = stringArray[index].toUpperCase()});
var string = stringArray.join('');
return string;
}

For taking an approach by iterating the characters, you could use a flag for the following upper case letter.
function toCamelCase(str) {
var upper = false;
return str
.split('')
.map(c => {
if (c === '-' || c === '_') {
upper = true;
return '';
}
if (upper) {
upper = false;
return c.toUpperCase();
}
return c;
})
.join('');
}
console.log(toCamelCase('foo----bar_baz'));

As strange as it sounds what fixed this error was to add ; semicolon at the end of line where the Parsing error: Invalid left-hand side in assignment expression occurred. More context here.

Related

Making any letter in () a lower case all other letters uppercase

I am trying to make a variable string uppercase and letters that are within () lower case. string will be what ever the user enters so do not know what it will be ahead of time.
user entry examples
What is entered
(H)e(L)lo
what is expected outcome
(h)E(l)LO
What is entered
(H)ELLO (W)orld
what is expected outcome
(h)ELLO (w)ORLD
here is what i have tried but can only get it to work if the () are at the end of the string.
if(getElementById("ID")){
var headline = getElementById("ID").getValue();
var headlineUpper = headline.toUpperCase();
var IndexOf = headlineUpper.indexOf("(");
if(IndexOf === -1){
template.getRegionNode("Region").setValue(headlineUpper);
}
else{
var plus = parseInt(IndexOf + 1);
var replacing = headlineUpper[plus];
var lower = replacing.toLowerCase();
var render = headlineUpper.replace(headlineUpper.substring(plus), lower + ")");
getElementById("Region").setValue(render);
}
}
Do to our system i am only able to use vanilla javascript. i have asked a similar question before with one () but now we are expecting more then one () in the string.
You can use the .replace() method with a regular expression. First you can make your string all uppercase using .toUpperCase(). Then, you can match all characters in-between ( and ) and use the replacement function of the replace method to convert the matched characters to lowercase.
See example below:
function uppercase(str) {
return str.toUpperCase().replace(/\(.*?\)/g, function(m) {
return m.toLowerCase();
});
}
console.log(uppercase("(H)e(L)lo")); // (h)E(l)LO
console.log(uppercase("(H)ELLO (W)orld")); // (h)ELLO (w)ORLD
If you can support ES6 you can clean up the above function with arrow functions:
const uppercase = str =>
str.toUpperCase().replace(/\(.*?\)/g, m => m.toLowerCase());
console.log(uppercase("(H)e(L)lo")); // (h)E(l)LO
console.log(uppercase("(H)ELLO (W)orld")); // (h)ELLO (w)ORLD
Just in case you want a faster regex alternative, you can use a negated character (^)) regex instead of laziness (?). It's faster as it doesn't require backtracking.
const uppercase = str =>
str.toUpperCase().replace(/\([^)]+\)/g, m => m.toLowerCase());
I tried to do it without use of any regex. I'm storing the indexes of all ( and ).
String.prototype.replaceBetween = function (start, end, what) {
return this.substring(0, start) + what + this.substring(end);
};
function changeCase(str) {
str = str.toLowerCase();
let startIndex = str.split('').map((el, index) => (el === '(') ? index : null).filter(el => el !== null);
let endIndex = str.split('').map((el, index) => (el === ')') ? index : null).filter(el => el !== null);
Array.from(Array(startIndex.length + 1).keys()).forEach(index => {
if (index !== startIndex.length) {
let indsideParentheses = '(' + str.substring(startIndex[index] + 1, endIndex[index]).toUpperCase() + ')';
str = str.replaceBetween(startIndex[index], endIndex[index] + 1, indsideParentheses);
}
});
return str;
}
let str = '(h)ELLO (w)ORLD'
console.log(changeCase(str));

How to get odd and even position characters from a string?

I'm trying to figure out how to remove every second character (starting from the first one) from a string in Javascript.
For example, the string "This is a test!" should become "hsi etTi sats!"
I also want to save every deleted character into another array.
I have tried using replace method and splice method, but wasn't able to get them to work properly. Mostly because replace only replaces the first character.
function encrypt(text, n) {
if (text === "NULL") return n;
if (n <= 0) return text;
var encArr = [];
var newString = text.split("");
var j = 0;
for (var i = 0; i < text.length; i += 2) {
encArr[j++] = text[i];
newString.splice(i, 1); // this line doesn't work properly
}
}
You could reduce the characters of the string and group them to separate arrays using the % operator. Use destructuring to get the 2D array returned to separate variables
let str = "This is a test!";
const [even, odd] = [...str].reduce((r,char,i) => (r[i%2].push(char), r), [[],[]])
console.log(odd.join(''))
console.log(even.join(''))
Using a for loop:
let str = "This is a test!",
odd = [],
even = [];
for (var i = 0; i < str.length; i++) {
i % 2 === 0
? even.push(str[i])
: odd.push(str[i])
}
console.log(odd.join(''))
console.log(even.join(''))
It would probably be easier to use a regular expression and .replace: capture two characters in separate capturing groups, add the first character to a string, and replace with the second character. Then, you'll have first half of the output you need in one string, and the second in another: just concatenate them together and return:
function encrypt(text) {
let removedText = '';
const replacedText1 = text.replace(/(.)(.)?/g, (_, firstChar, secondChar) => {
// in case the match was at the end of the string,
// and the string has an odd number of characters:
if (!secondChar) secondChar = '';
// remove the firstChar from the string, while adding it to removedText:
removedText += firstChar;
return secondChar;
});
return replacedText1 + removedText;
}
console.log(encrypt('This is a test!'));
Pretty simple with .reduce() to create the two arrays you seem to want.
function encrypt(text) {
return text.split("")
.reduce(({odd, even}, c, i) =>
i % 2 ? {odd: [...odd, c], even} : {odd, even: [...even, c]}
, {odd: [], even: []})
}
console.log(encrypt("This is a test!"));
They can be converted to strings by using .join("") if you desire.
I think you were on the right track. What you missed is replace is using either a string or RegExp.
The replace() method returns a new string with some or all matches of a pattern replaced by a replacement. The pattern can be a string or a RegExp, and the replacement can be a string or a function to be called for each match. If pattern is a string, only the first occurrence will be replaced.
Source: String.prototype.replace()
If you are replacing a value (and not a regular expression), only the first instance of the value will be replaced. To replace all occurrences of a specified value, use the global (g) modifier
Source: JavaScript String replace() Method
So my suggestion would be to continue still with replace and pass the right RegExp to the function, I guess you can figure out from this example - this removes every second occurrence for char 't':
let count = 0;
let testString = 'test test test test';
console.log('original', testString);
// global modifier in RegExp
let result = testString.replace(/t/g, function (match) {
count++;
return (count % 2 === 0) ? '' : match;
});
console.log('removed', result);
like this?
var text = "This is a test!"
var result = ""
var rest = ""
for(var i = 0; i < text.length; i++){
if( (i%2) != 0 ){
result += text[i]
} else{
rest += text[i]
}
}
console.log(result+rest)
Maybe with split, filter and join:
const remaining = myString.split('').filter((char, i) => i % 2 !== 0).join('');
const deleted = myString.split('').filter((char, i) => i % 2 === 0).join('');
You could take an array and splice and push each second item to the end of the array.
function encrypt(string) {
var array = [...string],
i = 0,
l = array.length >> 1;
while (i <= l) array.push(array.splice(i++, 1)[0]);
return array.join('');
}
console.log(encrypt("This is a test!"));
function encrypt(text) {
text = text.split("");
var removed = []
var encrypted = text.filter((letter, index) => {
if(index % 2 == 0){
removed.push(letter)
return false;
}
return true
}).join("")
return {
full: encrypted + removed.join(""),
encrypted: encrypted,
removed: removed
}
}
console.log(encrypt("This is a test!"))
Splice does not work, because if you remove an element from an array in for loop indexes most probably will be wrong when removing another element.
I don't know how much you care about performance, but using regex is not very efficient.
Simple test for quite a long string shows that using filter function is on average about 3 times faster, which can make quite a difference when performed on very long strings or on many, many shorts ones.
function test(func, n){
var text = "";
for(var i = 0; i < n; ++i){
text += "a";
}
var start = new Date().getTime();
func(text);
var end = new Date().getTime();
var time = (end-start) / 1000.0;
console.log(func.name, " took ", time, " seconds")
return time;
}
function encryptREGEX(text) {
let removedText = '';
const replacedText1 = text.replace(/(.)(.)?/g, (_, firstChar, secondChar) => {
// in case the match was at the end of the string,
// and the string has an odd number of characters:
if (!secondChar) secondChar = '';
// remove the firstChar from the string, while adding it to removedText:
removedText += firstChar;
return secondChar;
});
return replacedText1 + removedText;
}
function encrypt(text) {
text = text.split("");
var removed = "";
var encrypted = text.filter((letter, index) => {
if(index % 2 == 0){
removed += letter;
return false;
}
return true
}).join("")
return encrypted + removed
}
var timeREGEX = test(encryptREGEX, 10000000);
var timeFilter = test(encrypt, 10000000);
console.log("Using filter is faster ", timeREGEX/timeFilter, " times")
Using actually an array for storing removed letters and then joining them is much more efficient, than using a string and concatenating letters to it.
I changed an array to string in filter solution to make it the same like in regex solution, so they are more comparable.

How to correctly use Array.map() for replacing string with alphabet position

Other SO 'Replace string with alphabet positions' questions didn't utilize map, which is what I'm trying to learn how to use to solve this.
Problem:
Given a string, replace every letter with its position in the alphabet.
If anything in the text isn't a letter, ignore it and don't return it.
"a" = 1, "b" = 2, etc.
What I've tried is:
-looping over a new array instance and setting the index value to String.fromCharCode()
- taking input string making it lowercase
-splitting to array
-return array.map().join(' ')
function alphabetPosition(text) {
let alphabet = new Array(26);
for (let i = 0; i<26; ++i) {
let char = String.fromCharCode(97 + i);
alphabet[i] = char;
}
text = text.toLowerCase();
let arr = text.split('');
return arr.map(element => { return element = alphabet.indexOf(element+1) }).join(' ');
}
expected it to return a string of alphabet positions, but got nothing at all. What is wrong with my implementation of Array.map()?
In your map element would be a letter, "a" for example. Then you add (concat) 1 to it, which results in "a1" which is not in your alphabet. Also element = is unneccessary, returning the position is enough.
You've complicated the solution, the simplest approach would be to just find the charcode and return that.
function alphabetPosition(text) {
let str = '';
for (var i = 0; i < text.length; i++) {
str += (text[i] + (text.charCodeAt(i) - 96));
}
return str;
}
I totally understand that is a coding challenge, interview question or likewise so if you really need to use map() you should only return the result of the callback passed to map as follows :
return arr.map(x => alphabet.indexOf(x) + 1).join(' ')
However reduce() seems more appropriate in your case :
return arr.reduce((ac, cv) => ac + (alphabet.indexOf(cv) + 1) + ' ', '')
Your map() last line of the function was returning the value of
an assignment.
return arr.map(element => { return element = alphabet.indexOf(element+1) }).join(' ');
Just alphabet.indexOf(element) would have sufficed.
This will give you the result you want:
alphabetPosition = text => {
let alphabet = new Array(26);
for (let i = 0; i < 26; ++i) {
let char = String.fromCharCode(97 + i);
alphabet[i] = char;
}
return text.toLowerCase().split('').map(element =>
alphabet.indexOf(element)
).join(' ');
}
console.log(alphabetPosition("This is a string"));
Hope this helps,

Check if a String is a Palindrome in JavaScript

The requirements for this task are that the code is returns a 'true' or 'false' for an input string. The string can be a simply word or a phrase. The other question does not address these needs. Please reopen and answer here. I am working on a function to check if a given string is a palindrome. My code seems to work for simple one-word palindromes but not for palindromes that feature capitalization or spaces.
function palindrome(str)
{
var palin = str.split("").reverse().join("");
if (palin === str){
return true;
} else {
return false;
}
}
palindrome("eye");//Succeeds
palindrome("Race car");//Fails
First the string is converted to lowercase. Also, the characters that are not the alphabet are removed. So the string comparison becomes a array, then invert it, and convert it to string again.
Step 1: str1.toLowerCase().replace(...) => "Race car" => "race car" => "racecar"
Step 2: str2.split("") => ["r","a","c","e","c","a","r"] => .reverse().join() => "racecar"
Result: str1 === str2
function palindrome(str) {
str = str.toLowerCase().replace(/[^a-z]+/g,"");
return str === str.split("").reverse().join("")
}
alert(palindrome("eye")); //true
alert(palindrome("Race car")); //true
alert(palindrome("Madam, I'm Adam")); //true
Something like if (word === word.split('').reverse().join('')) {/*its a palindrome!*/} I'd say
An isPalindrome String extention:
String.prototype.isPalindrome = function () {
var cleaned = this.toLowerCase().match(/[a-z]/gi).reverse();
return cleaned.join('') === cleaned.reverse().join('');
}
var result = document.querySelector('#result');
result.textContent = "'eye'.isPalindrome() => " + 'eye'.isPalindrome() +
"\n'Something'.isPalindrome() => " + 'Something'.isPalindrome() +
"\n'Race Car'.isPalindrome() => " + 'Race Car'.isPalindrome() +
"\n'Are we not drawn onward, we few, drawn onward to new era?'.isPalindrome() => " +
'Are we not drawn onward, we few, drawn onward to new era?'.isPalindrome() +
"\n'Never even or odd'.isPalindrome() => " + 'Never even or odd'.isPalindrome() +
"\n'Never odd or even'.isPalindrome() => " + 'Never odd or even'.isPalindrome();
;
<pre id="result"></pre>
function palindrome(str) {
let letters = str.split('').filter(function (str) {
return /\S/.test(str);
});
let reversedLetters = str.split('').reverse().filter(function (str) {
return /\S/.test(str);
});
for (let i = 0; i < letters.length; i++) {
if (letters[i].toLowerCase() !== reversedLetters[i].toLowerCase()) {
return false;
}
}
return true;
}
console.log(palindrome("eye")); //true
console.log(palindrome('Race car')); //true
const palindromes = arrayOfWords.filter((item) => {
return item === item.split('').reverse().join('');
})
This is an example :-)
function palindrome(str) {
var st='';
st=str.replace(/[^a-z0-9]/ig,"").toLowerCase();
var arr=[];
arr=st.split('');
arr=arr.reverse();
var strr='';
strr=arr.join('');
if(strr==st) {
return true;
}
return false;
}
palindrome("A man, a plan, a canal. Panama");//calling the function
//1. change the string to an array
//2. use the reverse method
//3. return the array as a string
//4. return input= new reversed string
var lowerCasedString = inputString.toLowerCase();
var reversedString = lowerCasedString.split("").reverse().join("");
return reversedString === lowerCasedString;
}hope this would be helpful:
Palindrome using ES6
const checkPalindrome=(str)=> {
return str.toLowerCase().trim() === str.toLowerCase().trim().split('').reverse().join('');
}
console.log(checkPalindrome("Level "))
As easy as possible!
function checkStrForPalindorme(string) {
const str = string.toLowerCase().trim();
const reversedStr = str.split("").reverse().join("");
return str === reversedStr;
}
console.log(checkStrForPalindorme("aaffaa "))
console.log(checkStrForPalindorme("dummy"))
I have created a lookup object first and then analyze the frequency of each lookup item
if the str = "PEEPs", then
lookUp = {p:2, e:2, s:1}
Please refer to the following function for more details
function checkPlaindrome(str) {
const lookUp = {};
// Create the lookUp object
for (let char of str.toLowerCase().trim()) {
if (char !== " ") lookUp[char] = ++lookUp[char] || 1;
}
// Analyse the lookup object
const singleCharCheck = Object.values(lookUp).filter((val) => val === 1);
const findalSingleCharCheck =
singleCharCheck.length === 0 || singleCharCheck.length === 1;
const noneSingleCharCheck =
Object.values(lookUp)
.filter((val) => val !== 1)
.filter((val) => val % 2 !== 0).length === 0;
return findalSingleCharCheck && noneSingleCharCheck;
}
const r = checkPlaindrome("w wPEEPs"); // true
const r1 = checkPlaindrome("w PEEPs"); // false

How to find indices of all occurrences of one string in another in JavaScript?

I'm trying to find the positions of all occurrences of a string in another string, case-insensitive.
For example, given the string:
I learned to play the Ukulele in Lebanon.
and the search string le, I want to obtain the array:
[2, 25, 27, 33]
Both strings will be variables - i.e., I can't hard-code their values.
I figured that this was an easy task for regular expressions, but after struggling for a while to find one that would work, I've had no luck.
I found this example of how to accomplish this using .indexOf(), but surely there has to be a more concise way to do it?
var str = "I learned to play the Ukulele in Lebanon."
var regex = /le/gi, result, indices = [];
while ( (result = regex.exec(str)) ) {
indices.push(result.index);
}
UPDATE
I failed to spot in the original question that the search string needs to be a variable. I've written another version to deal with this case that uses indexOf, so you're back to where you started. As pointed out by Wrikken in the comments, to do this for the general case with regular expressions you would need to escape special regex characters, at which point I think the regex solution becomes more of a headache than it's worth.
function getIndicesOf(searchStr, str, caseSensitive) {
var searchStrLen = searchStr.length;
if (searchStrLen == 0) {
return [];
}
var startIndex = 0, index, indices = [];
if (!caseSensitive) {
str = str.toLowerCase();
searchStr = searchStr.toLowerCase();
}
while ((index = str.indexOf(searchStr, startIndex)) > -1) {
indices.push(index);
startIndex = index + searchStrLen;
}
return indices;
}
var indices = getIndicesOf("le", "I learned to play the Ukulele in Lebanon.");
document.getElementById("output").innerHTML = indices + "";
<div id="output"></div>
One liner using String.prototype.matchAll (ES2020):
[...sourceStr.matchAll(new RegExp(searchStr, 'gi'))].map(a => a.index)
Using your values:
const sourceStr = 'I learned to play the Ukulele in Lebanon.';
const searchStr = 'le';
const indexes = [...sourceStr.matchAll(new RegExp(searchStr, 'gi'))].map(a => a.index);
console.log(indexes); // [2, 25, 27, 33]
If you're worried about doing a spread and a map() in one line, I ran it with a for...of loop for a million iterations (using your strings). The one liner averages 1420ms while the for...of averages 1150ms on my machine. That's not an insignificant difference, but the one liner will work fine if you're only doing a handful of matches.
See matchAll on caniuse
Here is regex free version:
function indexes(source, find) {
if (!source) {
return [];
}
// if find is empty string return all indexes.
if (!find) {
// or shorter arrow function:
// return source.split('').map((_,i) => i);
return source.split('').map(function(_, i) { return i; });
}
var result = [];
for (i = 0; i < source.length; ++i) {
// If you want to search case insensitive use
// if (source.substring(i, i + find.length).toLowerCase() == find) {
if (source.substring(i, i + find.length) == find) {
result.push(i);
}
}
return result;
}
indexes("I learned to play the Ukulele in Lebanon.", "le")
EDIT: and if you want to match strings like 'aaaa' and 'aa' to find [0, 2] use this version:
function indexes(source, find) {
if (!source) {
return [];
}
if (!find) {
return source.split('').map(function(_, i) { return i; });
}
var result = [];
var i = 0;
while(i < source.length) {
if (source.substring(i, i + find.length) == find) {
result.push(i);
i += find.length;
} else {
i++;
}
}
return result;
}
You sure can do this!
//make a regular expression out of your needle
var needle = 'le'
var re = new RegExp(needle,'gi');
var haystack = 'I learned to play the Ukulele';
var results = new Array();//this is the results you want
while (re.exec(haystack)){
results.push(re.lastIndex);
}
Edit: learn to spell RegExp
Also, I realized this isn't exactly what you want, as lastIndex tells us the end of the needle not the beginning, but it's close - you could push re.lastIndex-needle.length into the results array...
Edit: adding link
#Tim Down's answer uses the results object from RegExp.exec(), and all my Javascript resources gloss over its use (apart from giving you the matched string). So when he uses result.index, that's some sort of unnamed Match Object. In the MDC description of exec, they actually describe this object in decent detail.
I am a bit late to the party (by almost 10 years, 2 months), but one way for future coders is to do it using while loop and indexOf()
let haystack = "I learned to play the Ukulele in Lebanon.";
let needle = "le";
let pos = 0; // Position Ref
let result = []; // Final output of all index's.
let hayStackLower = haystack.toLowerCase();
// Loop to check all occurrences
while (hayStackLower.indexOf(needle, pos) != -1) {
result.push(hayStackLower.indexOf(needle , pos));
pos = hayStackLower.indexOf(needle , pos) + 1;
}
console.log("Final ", result); // Returns all indexes or empty array if not found
If you just want to find the position of all matches I'd like to point you to a little hack:
var haystack = 'I learned to play the Ukulele in Lebanon.',
needle = 'le',
splitOnFound = haystack.split(needle).map(function (culm)
{
return this.pos += culm.length + needle.length
}, {pos: -needle.length}).slice(0, -1); // {pos: ...} – Object wich is used as this
console.log(splitOnFound);
It might not be applikable if you have a RegExp with variable length but for some it might be helpful.
This is case sensitive. For case insensitivity use String.toLowerCase function before.
const findAllOccurrences = (str, substr) => {
str = str.toLowerCase();
let result = [];
let idx = str.indexOf(substr)
while (idx !== -1) {
result.push(idx);
idx = str.indexOf(substr, idx+1);
}
return result;
}
console.log(findAllOccurrences('I learned to play the Ukulele in Lebanon', 'le'));
I would recommend Tim's answer. However, this comment by #blazs states "Suppose searchStr=aaa and that str=aaaaaa. Then instead of finding 4 occurences your code will find only 2 because you're making skips by searchStr.length in the loop.", which is true by looking at Tim's code, specifically this line here: startIndex = index + searchStrLen; Tim's code would not be able to find an instance of the string that's being searched that is within the length of itself. So, I've modified Tim's answer:
function getIndicesOf(searchStr, str, caseSensitive) {
var startIndex = 0, index, indices = [];
if (!caseSensitive) {
str = str.toLowerCase();
searchStr = searchStr.toLowerCase();
}
while ((index = str.indexOf(searchStr, startIndex)) > -1) {
indices.push(index);
startIndex = index + 1;
}
return indices;
}
var searchStr = prompt("Enter a string.");
var str = prompt("What do you want to search for in the string?");
var indices = getIndicesOf(str, searchStr);
document.getElementById("output").innerHTML = indices + "";
<div id="output"></div>
Changing it to + 1 instead of + searchStrLen will allow the index 1 to be in the indices array if I have an str of aaaaaa and a searchStr of aaa.
P.S. If anyone would like comments in the code to explain how the code works, please say so, and I'll be happy to respond to the request.
Here is a simple code snippet:
function getIndexOfSubStr(str, searchToken, preIndex, output) {
var result = str.match(searchToken);
if (result) {
output.push(result.index +preIndex);
str=str.substring(result.index+searchToken.length);
getIndexOfSubStr(str, searchToken, preIndex, output)
}
return output;
}
var str = "my name is 'xyz' and my school name is 'xyz' and my area name is 'xyz' ";
var searchToken ="my";
var preIndex = 0;
console.log(getIndexOfSubStr(str, searchToken, preIndex, []));
Thanks for all the replies. I went through all of them and came up with a function that gives the first an last index of each occurrence of the 'needle' substring . I am posting it here in case it will help someone.
Please note, it is not the same as the original request for only the beginning of each occurrence. It suits my usecase better because you don't need to keep the needle length.
function findRegexIndices(text, needle, caseSensitive){
var needleLen = needle.length,
reg = new RegExp(needle, caseSensitive ? 'gi' : 'g'),
indices = [],
result;
while ( (result = reg.exec(text)) ) {
indices.push([result.index, result.index + needleLen]);
}
return indices
}
Check this solution which will able to find same character string too, let me know if something missing or not right.
function indexes(source, find) {
if (!source) {
return [];
}
if (!find) {
return source.split('').map(function(_, i) { return i; });
}
source = source.toLowerCase();
find = find.toLowerCase();
var result = [];
var i = 0;
while(i < source.length) {
if (source.substring(i, i + find.length) == find)
result.push(i++);
else
i++
}
return result;
}
console.log(indexes('aaaaaaaa', 'aaaaaa'))
console.log(indexes('aeeaaaaadjfhfnaaaaadjddjaa', 'aaaa'))
console.log(indexes('wordgoodwordgoodgoodbestword', 'wordgood'))
console.log(indexes('I learned to play the Ukulele in Lebanon.', 'le'))
Follow the answer of #jcubic, his solution caused a small confusion for my case
For example var result = indexes('aaaa', 'aa') will return [0, 1, 2] instead of [0, 2]
So I updated a bit his solution as below to match my case
function indexes(text, subText, caseSensitive) {
var _source = text;
var _find = subText;
if (caseSensitive != true) {
_source = _source.toLowerCase();
_find = _find.toLowerCase();
}
var result = [];
for (var i = 0; i < _source.length;) {
if (_source.substring(i, i + _find.length) == _find) {
result.push(i);
i += _find.length; // found a subText, skip to next position
} else {
i += 1;
}
}
return result;
}
Here's my code (using search and slice methods)
let s = "I learned to play the Ukulele in Lebanon"
let sub = 0
let matchingIndex = []
let index = s.search(/le/i)
while( index >= 0 ){
matchingIndex.push(index+sub);
sub = sub + ( s.length - s.slice( index+1 ).length )
s = s.slice( index+1 )
index = s.search(/le/i)
}
console.log(matchingIndex)
This is what I usually use to get a string index also according to its position.
I pass following parameters:
search: the string where to search for
find: the string to find
position ('all' by default): the position by which the find string appears in search string
(if 'all' it returns the complete array of indexes)
(if 'last' it returns the last position)
function stringIndex (search, find, position = "all") {
var currIndex = 0, indexes = [], found = true;
while (found) {
var searchIndex = search.indexOf(find);
if (searchIndex > -1) {
currIndex += searchIndex + find.length;
search = search.substr (searchIndex + find.length);
indexes.push (currIndex - find.length);
} else found = false; //no other string to search for - exit from while loop
}
if (position == 'all') return indexes;
if (position > indexes.length -1) return [];
position = (position == "last") ? indexes.length -1 : position;
return indexes[position];
}
//Example:
var myString = "Joe meets Joe and together they go to Joe's house";
console.log ( stringIndex(myString, "Joe") ); //0, 10, 38
console.log ( stringIndex(myString, "Joe", 1) ); //10
console.log ( stringIndex(myString, "Joe", "last") ); //38
console.log ( stringIndex(myString, "Joe", 5) ); //[]
Hi friends this is just another way of finding indexes of matching phrase using reduce and a helper method. Of course RegExp is more convenient and perhaps is internally implemented somehow like this. I hope you find it useful.
function findIndexesOfPhraseWithReduce(text, phrase) {
//convert text to array so that be able to manipulate.
const arrayOfText = [...text];
/* this function takes the array of characters and
the search phrase and start index which comes from reduce method
and calculates the end with length of the given phrase then slices
and joins characters and compare it whith phrase.
and returns True Or False */
function isMatch(array, phrase, start) {
const end = start + phrase.length;
return (array.slice(start, end).join('')).toLowerCase() ===
phrase.toLowerCase();
}
/* here we reduce the array of characters and test each character
with isMach function which takes "current index" and matches the phrase
with the subsequent character which starts from current index and
ends at the last character of phrase(the length of phrase). */
return arrayOfText.reduce((acc, item, index) => isMatch(arrayOfText, phrase,
index) ? [...acc, index] : acc, []);
}
findIndexesOfPhraseWithReduce("I learned to play the Ukulele in Lebanon.", "le");
function findIndexesOfPhraseWithReduce(text, phrase) {
const arrayOfText = [...text];
function isMatch(array, phrase, start) {
const end = start + phrase.length;
return (array.slice(start, end).join('')).toLowerCase() ===
phrase.toLowerCase();
}
return arrayOfText.reduce((acc, item, index) => isMatch(arrayOfText, phrase,
index) ? [...acc, index] : acc, []);
}
console.log(findIndexesOfPhraseWithReduce("I learned to play the Ukulele in Lebanon.", "le"));
function countInString(searchFor,searchIn){
var results=0;
var a=searchIn.indexOf(searchFor)
while(a!=-1){
searchIn=searchIn.slice(a*1+searchFor.length);
results++;
a=searchIn.indexOf(searchFor);
}
return results;
}
the below code will do the job for you :
function indexes(source, find) {
var result = [];
for(i=0;i<str.length; ++i) {
// If you want to search case insensitive use
// if (source.substring(i, i + find.length).toLowerCase() == find) {
if (source.substring(i, i + find.length) == find) {
result.push(i);
}
}
return result;
}
indexes("hello, how are you", "ar")
Use String.prototype.match.
Here is an example from the MDN docs itself:
var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
var regexp = /[A-E]/gi;
var matches_array = str.match(regexp);
console.log(matches_array);
// ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e']

Categories

Resources