I have this JavaScript:
var str = "abcdefoihewfojias".split('');
for (var i = 0; i < str.length; i++) {
var xp = str[i] = "|";
}
alert( str.join("") );
I aim to replace every fourth letter in the string abcdefoihewfojias with |, so it becomes abc|efo|....etc,but I do not have a clue how to do this.
You could just do it with a regex replace:
var str = "abcdefoihewfojias";
var result = str.replace(/(...)./g, "$1|");
console.log(result);
To support re-usability and the option to wrap this in an object/function let's parameterise it:
var str = "abcdefoihewfojias".split('');
var nth = 4; // the nth character you want to replace
var replaceWith = "|" // the character you want to replace the nth value
for (var i = nth-1; i < str.length-1; i+=nth) {
str[i] = replaceWith;
}
alert( str.join("") );
This might help you solve your problem
var str = "abcdefoihewfojias".split("");
for (var i = 3; i < str.length - 1; i+=4) {
str[i] = "|";
}
alert( str.join("") );
You go with for loop from the the first char that you want to replace (the 3 char) until the one digit before the end and replace every 4 places.
If the for loop will go from the str.length and not to str.length-1 sometimes at the last char will be |.
.map one-liner
You can use this one-liner:
var str = "abcdefoihewfojias";
str.split('').map(function(l,i) {
return (i + 1) % 4 ? l : '|';
}).join('');
% returns the remainder. So:
# | Result (# + 1) % 4
---|-------
0 | 1
1 | 2
2 | 3
4 | 0 // Bingo!
ES6 alternative
With ES6, you can do:
[...str].map((l,i) => (i + 1) % 4 ? l : '|')
Simple just use modulus
https://jsfiddle.net/ctfsorwg/
var str = "abcdefoihewfojias";
var outputStr = str.split("");
for (var i = 0; i < outputStr.length; i++) {
if(!((i+1)%4))outputStr[i] = '|';
}
alert( "Before: " + str + "\nAfter: " + outputStr.join(""));
While there are several answers already, I thought I'd offer a slightly alternative approach, using Array.prototype.map(), wrapped in a function that can be adapted by the user (to update the value of n in the nth character, and change the replacement character used):
// defining the named function, with an 'opts' argument:
function replaceNthWith(opts) {
// setting the default options:
var defaults = {
// defining the nth character, in this case
// every fourth:
'nth': 4,
// defining the character to replace that
// nth character with:
'char': '|'
};
// Note that there's no default string argument,
// so that one argument must be provided in the
// opts object.
// iterating over each property in the
// opts Object:
for (var property in opts) {
// if the current property is a property of
// this Object, not inherited from the Object
// prototype:
if (opts.hasOwnProperty(property)) {
// we set that property of the defaults
// Object to be equal to that property
// as set in the opts Object:
defaults[property] = opts[property];
}
}
// if there is a defaults.string property
// (inherited from the opts.string property)
// then we go ahead; otherwise nothing happens
// note: this property must be set for the
// function to do anything useful:
if (defaults.string) {
// here we split the string supplied from the user,
// via opts.string, in defaults.string to form an
// Array of characters; we iterate over that Array
// with Array.prototype.map(), which process one
// Array and returns a new Array according to the
// anonymous function supplied:
return haystack = defaults.string.split('').map(function(character, index) {
// here, when the index of the current letter in the
// Array formed by Array.prototype.split() plus 1
// (JavaScript is zero-based) divided by the number
// held in defaults.nth is equal to zero - ensuring
// that the current letter is the 'nth' index we return
// the defaults.char character; otherwise we return
// the original character from the Array over which
// we're iterating:
return (index + 1) % parseInt(defaults.nth) === 0 ? defaults.char : character;
// here we join the Array back into a String, using
// Array.prototype.join() with an empty string:
}).join('');
}
}
// 'snippet.log()' is used only in this demonstration, in real life use
// 'console.log()', or print to screen or display in whatever other
// method you prefer:
snippet.log( replaceNthWith({ 'string': "abcdefoihewfojias" }) );
function replaceNthWith(opts) {
var defaults = {
'nth': 4,
'char': '|'
};
for (var property in opts) {
if (opts.hasOwnProperty(property)) {
defaults[property] = opts[property];
}
}
if (defaults.string) {
return haystack = defaults.string.split('').map(function(character, index) {
return (index + 1) % parseInt(defaults.nth) === 0 ? defaults.char : character;
}).join('');
}
}
// 'snippet.log()' is used only in this demonstration, in real life use
// 'console.log()', or print to screen or display in whatever other
// method you prefer.
// calling the function, passing in the supplied 'string'
// property value:
snippet.log( replaceNthWith({
'string': "abcdefoihewfojias"
}) );
// outputs: abc|efo|hew|oji|s
// calling the function with the same string, but to replace
// every second character ( 'nth' : 2 ):
snippet.log( replaceNthWith({
'string': "abcdefoihewfojias",
'nth': 2
}) );
// outputs: a|c|e|o|h|w|o|i|s
// passing in the same string once again, working on every
// third character, and replacing with a caret ('^'):
snippet.log( replaceNthWith({
'string': "abcdefoihewfojias",
'nth': 3,
'char' : '^'
}) );
// outputs: ab^de^oi^ew^oj^as
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
References:
Array.prototype.map().
Array.prototype.join().
for...in loop.
JavaScript Remainder (%) operator.
Object.prototype.hasOwnProperty().
String.prototype.split().
function replaceWith(word,nth, replaceWithCh) {
//match nth position globally
//'\S' is for non-whitespace
let regex = new RegExp("(\\S{" + (nth - 1) + "})\\S", "g");
// '$1' means single group
// after each group position replaceWithCharecter
let _word = word.replace(regex, "$1" + replaceWithCh);
return _word;
}
const str = "abcdefoihewfojias";
const result = replaceWith(str, 3, "X");
console.log(result);
Related
I need to iterate over an input string and return a string with the count of the frequency of the different vowels in the string. The vowels in the return string should be in the order they appear in the input string. So, if 'hello world' is the function's parameter, the function should return e1o2. The code I have so far is below. It returns e1o2o3. For some reason, it is not stopping the count of o after it hits the o in hello, and seems to be counting the o in world as a separate count. I think it is, finalString += char + sum;, that is causing this. But, I do not know how to create this function in the first place. Thank you for your time.
function vowelFrequency(str) {
let finalString = '';
let sum = 0;
for (let char of str) {
if ('aeiou'.includes(char)) {
sum += 1;
finalString += char + sum;
}
}
return finalString;
};
The main problem is your sum counter. It counts all vowels together.
Better appoach would be to create a dictionary of vowels
where we add +1 every time we met a match.
In short the idea is:
if (char === 'e') {
dic['e'] += 1;
}
const text = 'hello world';
function vowelFrequency(str) {
let finalString = '';
let dic = {};
for (let char of str) {
if ('aeiou'.includes(char)) {
//check if dictionary has no certain vowel
//it happens when we first time meet a vowel
if (!(char in dic)) {
dic[char] = 0;
}
//increment our counter
dic[char]+=1;
}
}
//by the end of the loop
//we have object with { e: 1, o: 2 }
//now we need to gather values into string
//loop through the object
for ([char, count] of Object.entries(dic)) {
finalString += char + count;
}
return finalString;
};
console.log(vowelFrequency(text));
Shorter version of the same solution would be:
function vowelFrequency(str) {
const vowels = 'aeiou';
let dic = [...str].reduce((dic, char) => {
if (vowels.includes(char))
dic[char] = dic[char] + 1 || 1;
return dic;
}, {});
return Object.entries(dic)
.map(([char, count]) => `${char}${count}`)
.join('');
};
One concise approach would be to transform the string via String.prototype.replaceAll (evaluating every character in the string). The following code searches the original string (which you may wish to normalize beforehand with .toLowerCase() for better results) for any character.
"hello world".replaceAll(/./g, ( char, index, str ) =>
!'aeiou'.includes( char ) || str.lastIndexOf( char ) > index
? "" : char + [ ...str ].filter( o => o == char ).length
);
Each character is checked against a list of vowels. We also check to see if the character index is the last index of this character (does it appear multiple times) in the original string. If either of these conditions fail, an empty string is returned in the character's place.
If our character is in our vowel list, and is the last instance of itself, then we split the original string, filter-out non-matching characters, and return the final count of character instances.
The above approach is somewhat of a gimmick. It's concise, but probably not very self-explanatory or maintainable. Realistically, you'd want to take a slightly more verbose approach (see below).
Note that Map is preferred over a standard object to ensure that key-insertion order is preserved.
function charInstanceString ( input, chars = "aeiou" ) {
/**
* Cycle over each character in our string, checking
* if it appears in our `chars` string. If the character
* appears in our `chars` string, we'll update our map
* to reflect the number of instances for the character.
*/
const charMap = new Map();
for ( const char of input ) {
if ( !chars.includes( char ) ) continue;
charMap.set( char, charMap.get( char ) + 1 || 1 );
}
/**
* Cycle over our map, adding each character (and its
* corresponding count) to an output string.
*/
let output = "";
for ( const [ char, count ] of charMap ) {
output += `${ char }${ count }`;
}
return output;
}
I need help Writing a function subLength() that takes 2 parameters, a string and a single character. The function should search the string for the two occurrences of the character and return the length between them including the 2 characters. If there are less than 2 or more than 2 occurrences of the character the function should return 0. How can I solve this problem using loops?
subLength('Saturday', 'a'); // returns 6
subLength('summer', 'm'); // returns 2
subLength('digitize', 'i'); // returns 0
subLength('cheesecake', 'k'); // returns 0
Here I loop through the characters of the string to find each value that is the char.
if the length isn't 2, return 0.
using slice, get only the characters within the two found indexs and get that length adding one to fix the offset
const subLength = (str, char) => {
let strChars = str.toLowerCase().split(""),
found = [],
length = 0;
strChars.forEach((val, index) => {
if (val === char) {
found.push(index);
}
});
if (found.length != 2) {
return length;
}
return str.slice(found[0], found[1]).length + 1;
}
console.log(subLength('Saturday', 'a')); // returns 6
console.log(subLength('summer', 'm')); // returns 2
console.log(subLength('digitize', 'i')); // returns 0
console.log(subLength('cheesecake', 'k')); // returns 0
You can try this logic:
Loop over string and count number of occurance
if count is 2,
Create a regex to capture the string in between.
Return its length
Else return 0
function subLength(str, char) {
let length = 0;
const occuranceCount = Array
.from(str)
.filter((c) => c.toLowerCase() === char.toLowerCase())
.length
if (occuranceCount === 2) {
const regex = new RegExp(`${char}(.*)${char}`)
length = str.match(regex)[0].length
}
console.log(length)
return length;
}
subLength('Saturday', 'a'); // returns 6
subLength('summer', 'm'); // returns 2
subLength('digitize', 'i'); // returns 0
subLength('cheesecake', 'k'); // returns 0
Using just for loop:
function subLength(str, char) {
let count = 0;
let initPosition;
let lastPosition;
for (let i = 0; i < str.length; i++) {
if (str[i] === char) {
count++
if (count > 2) {
return 0;
}
if (initPosition === undefined) {
initPosition = i
} else {
lastPosition = i+1
}
}
}
return count < 2 ? 0 : lastPosition - initPosition;
}
console.log(subLength('Saturday', 'a')); // returns 6
console.log(subLength('summer', 'm')); // returns 2
console.log(subLength('digitize', 'i')); // returns 0
console.log(subLength('cheesecake', 'k')); // returns 0
I too am going through the Codecademy course where this question came up which led me to this post.
Using the RegExp solution provided by #Rajesh (thank you!!) I started to break it down to better understand what was going on and making notes/comments because I am still pretty new and haven't used or been exposed to some of these things.
At the end of it all I thought I'd share what I ended up with in case anyone found it helpful.
function subLength(str, char) {
// Outputting to the console what we are looking for given the value of the string and character from the test cases at the end of this script.
console.log(`Showing the subLength for the string: "${str}" between "${char}" and "${char}" including the "${char}" positions.`);
// create the length variable which will be returned by the function
let length = 0;
// ** Search the string for the two occurrences of the character and count them. Then assign the result to the occurrenceCount variable for use in the if else statement.
// The "Array" class is a global object that is used in the construction off arrays.
// The Array.from() static method creates a new, shallow-copied Array instance from an array-like or iterable object.
// The Array.filter() method creates a new array with all elements that pass the test implemented by the provided function. The "c" represents each element of the array/string which is then compared to the char variable. if it is a match it gets added to the Array. We use .toLowerCase on both to ensure case compatibility.
// Appending the Array with ".length" assigns occurrenceCount the numeric value of the array's length rather than the array of characters.
const occurrenceCount = Array.from(str).filter((c) => c.toLowerCase() === char.toLowerCase());
console.log(' The contents of the occurrenceCountArray = ' + occurrenceCount);
console.log(' The character occurrence count = ' + occurrenceCount.length);
// if the string has two occurrences : return the length between them including the two characters : else the string has less than 2 or more than 2 characters : return 0.
if (occurrenceCount.length === 2) {
// The RegExp object is used for matching text with a pattern. The "(.*)" in between the ${char}'s will match and capture as much as possible aka greedy match. "()" = capture anything matched. (" = start of group. "." = match any character. "*" = Greedy match that matches everything in place of the "*". ")" = end of group.
const regex = new RegExp(`${char}(.*)${char}`);
// log to console the pattern being matched
console.log(` regex pattern to find = ${regex}`);
// log to the console the [0] = index 0 pattern that was captured from the string using str.match(regex)[0]
console.log(` regex output = ${str.match(regex)[0]}`);
// Use".length" to count the number of characters in the regex string at index 0 of the regex array and assign that value to the length variable.
length = str.match(regex)[0].length;
// Output the results to the console
console.log(` The distance from "${char}" to "${char}" (including the "${char}" positions) in the string: ${str} = ${length}\n`);
// return the length value
return length;
} else {
// Output the results to the console
console.log(` The string either has too many or too few occurrences.\n The subLength = ${length}\n`);
// return the length value
return length;
}
}
// test cases
subLength('Saturday', 'a'); // returns 6
subLength('summer', 'm'); // returns 2
subLength('digitize', 'i'); // returns 0
subLength('cheesecake', 'k'); // returns 0
The answer I am getting is this:
const subLength = (str, char) => {
let charCount = 0;
let len = -1;
for (let i=0; i<str.length; i++) {
if (str[i] == char) {
charCount++;
if (charCount > 2) {
return 0;
}
if (len == -1) {
len = i;
} else {
len = i - len + 1
}
}
}
if (charCount < 2) {
return 0;
}
return len;
};
It is better to try yourself a solution first. It is a very bad practice to just ask a solution for your homework!!!
Even if the solution can be JUST a few lines of code i wrote for you with commments a working solution :
const subLength = (str,char) => {
// create an empty array
const strarr = [];
// push string into array
strarr.push(str);
//initiate a count variable
let count = 0;
// WRITE YOUR REGULAR EXPRESSION
// Using the regular expression constructor - new RegExp("ab{2}", "g") .
const regString = `[${char}]`;
const regex = new RegExp(regString, "g");
// iterate through the string array to
for (let i = 0; i < strarr.length; i++) {
// calculate how many time the character occurs
count = (strarr[i].match(regex) || []).length;
};
// check with if condition
//if count is 2
if (count === 2) {
// calculate the index of first ocurrance of the string
first = str.indexOf(char);
// calculate the index of second ocurrance of the string
second = str.lastIndexOf(char);
// calculate the distance between them
return second - first + 1;
// if count is greater than two return 0
}
else if (count > 2) {
return count = 0;
}
// if count is less than two return 0
else if (count < 2) {
return 0;
}
};
console.log(subLength("iiiiliiile","l"));
I just answered this problem in codeAcademy and this is the solution that I came up with, just using if-statements and string.indexOf
const subLength = (strng, char) => {
let firstIndex = strng.indexOf(char);
let secondIndex = strng.indexOf(char, (firstIndex + 1));
let thirdIndex = strng.indexOf(char, (secondIndex + 1));
if (firstIndex === -1){
return 0
} else if (secondIndex === -1){
return 0
} else if (thirdIndex === -1 ){
return (secondIndex - firstIndex + 1)
} else {
return 0
};
};
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.
I want to count the number of occurrences of a string at the end of the string. I want it to ignore occurrences that are not at the end and I want it to return zero if there are none.
terminal string to find: "-1"
e.g. string = 1
// 0
e.g. string = 1-1
// 1
e.g. string = 1-1-1
// 2
e.g. string = 1-2-1
// 1
e.g. string = 1-2-1-2-1
// 1
e.g. string = 2-1-1-1-1
// 4
e.g. string = 1-1-2
// 0
I want it to count all of the occurrences at the end of the string, not just the occurrences anywhere in the string.
I tried:
var occurrences = string.match(/(-1)*$/).length;
I have a JS Fiddle here: JS Fiddle
It returns "2", no matter what my string.
You need to work on the first element of the returned array:
string.match(/(-1)*$/)[0].length/2
Find the length of first element which is the matched string of "-1" at the end and divide by 2 since the string "-1" is of length 2.
To quote from MDN String.prototype.match():
Return value
If the string matches the expression, it will return an Array
containing the entire matched string as the first element, followed by
any results captured in parentheses. If there were no matches, null is
returned.
function count() {
console.log(string.match(/(-1)*$/)[0].length / 2)
}
var string = "1"
// 0
count();
string = "1-1"
// 1
count();
string = "1-1-1"
// 2
count();
string = "1-2-1"
// 1
count();
string = "1-2-1-2-1"
// 1
count();
string = "2-1-1-1-1"
// 4
count();
string = "1-1-2"
// 0
count();
Walk backwards and count?
var string = "2-1-1-1-1";
var find = "-1";
var match = 0;
for (var i = string.length; i >= 0; i -= find.length) {
if (string.substr(i - find.length, find.length) == find)
match++;
else
break;
}
console.log("="+match)
Use String#match to find the chain of -1 that reaches the end, then split by -1, and get the length -1. When you split an a string of -1-1-1 you'll get an array with four items. Now we can extract the length, and reduce it by one.
function m(str) {
return str.match(/(-1)*$/g)[0].split(-1).length - 1;
}
console.log(m('1')) // 0
console.log(m('1-1')) // 1
console.log(m('1-1-1')) // 2
console.log(m('1-2-1')) // 1
console.log(m('1-2-1-2-1')) // 1
console.log(m('2-1-1-1-1')) // 4
console.log(m('1-1-2')) // 0
Try this. This runs Ok for all of your tested values
function countOnesAtTheEnd(s){
var array = s.split("-");
var count = 0;
for(var i =1; i<array.length; i++)
{
if(array[i] =="1"){
count++;
}
else count = 0;
}
console.log(count);
}
countOnesAtTheEnd("1");
countOnesAtTheEnd("1-1");
countOnesAtTheEnd("1-1-1");
countOnesAtTheEnd("1-2-1");
countOnesAtTheEnd("1-2-1-2-1");
countOnesAtTheEnd("2-1-1-1-1");
countOnesAtTheEnd("1-1-2");
Non regex version:
var occurences = 0;
string.split("-1").reduceRight((exit, space) => {
if(exit || space) return true;
occurences++;
return false;
}, false);
How can I insert a string at a specific index of another string?
var txt1 = "foo baz"
Suppose I want to insert "bar " after the "foo" how can I achieve that?
I thought of substring(), but there must be a simpler more straight forward way.
Inserting at a specific index (rather than, say, at the first space character) has to use string slicing/substring:
var txt2 = txt1.slice(0, 3) + "bar" + txt1.slice(3);
You could prototype your own splice() into String.
Polyfill
if (!String.prototype.splice) {
/**
* {JSDoc}
*
* The splice() method changes the content of a string by removing a range of
* characters and/or adding new characters.
*
* #this {String}
* #param {number} start Index at which to start changing the string.
* #param {number} delCount An integer indicating the number of old chars to remove.
* #param {string} newSubStr The String that is spliced in.
* #return {string} A new string with the spliced substring.
*/
String.prototype.splice = function(start, delCount, newSubStr) {
return this.slice(0, start) + newSubStr + this.slice(start + Math.abs(delCount));
};
}
Example
String.prototype.splice = function(idx, rem, str) {
return this.slice(0, idx) + str + this.slice(idx + Math.abs(rem));
};
var result = "foo baz".splice(4, 0, "bar ");
document.body.innerHTML = result; // "foo bar baz"
EDIT: Modified it to ensure that rem is an absolute value.
Here is a method I wrote that behaves like all other programming languages:
String.prototype.insert = function(index, string) {
if (index > 0)
{
return this.substring(0, index) + string + this.substring(index, this.length);
}
return string + this;
};
//Example of use:
var something = "How you?";
something = something.insert(3, " are");
console.log(something)
Reference:
http://coderamblings.wordpress.com/2012/07/09/insert-a-string-at-a-specific-index/
Just make the following function:
function insert(str, index, value) {
return str.substr(0, index) + value + str.substr(index);
}
and then use it like that:
alert(insert("foo baz", 4, "bar "));
Output: foo bar baz
It behaves exactly, like the C# (Sharp) String.Insert(int startIndex, string value).
NOTE: This insert function inserts the string value (third parameter) before the specified integer index (second parameter) in the string str (first parameter), and then returns the new string without changing str!
UPDATE 2016: Here is another just-for-fun (but more serious!) prototype function based on one-liner RegExp approach (with prepend support on undefined or negative index):
/**
* Insert `what` to string at position `index`.
*/
String.prototype.insert = function(what, index) {
return index > 0
? this.replace(new RegExp('.{' + index + '}'), '$&' + what)
: what + this;
};
console.log( 'foo baz'.insert('bar ', 4) ); // "foo bar baz"
console.log( 'foo baz'.insert('bar ') ); // "bar foo baz"
Previous (back to 2012) just-for-fun solution:
var index = 4,
what = 'bar ';
'foo baz'.replace(/./g, function(v, i) {
return i === index - 1 ? v + what : v;
}); // "foo bar baz"
This is basically doing what #Base33 is doing except I'm also giving the option of using a negative index to count from the end. Kind of like the substr method allows.
// use a negative index to insert relative to the end of the string.
String.prototype.insert = function (index, string) {
var ind = index < 0 ? this.length + index : index;
return this.substring(0, ind) + string + this.substr(ind);
};
Example:
Let's say you have full size images using a naming convention but can't update the data to also provide thumbnail urls.
var url = '/images/myimage.jpg';
var thumb = url.insert(-4, '_thm');
// result: '/images/myimage_thm.jpg'
If anyone is looking for a way to insert text at multiple indices in a string, try this out:
String.prototype.insertTextAtIndices = function(text) {
return this.replace(/./g, function(character, index) {
return text[index] ? text[index] + character : character;
});
};
For example, you can use this to insert <span> tags at certain offsets in a string:
var text = {
6: "<span>",
11: "</span>"
};
"Hello world!".insertTextAtIndices(text); // returns "Hello <span>world</span>!"
Instantiate an array from the string
Use Array#splice
Stringify again using Array#join
The benefits of this approach are two-fold:
Simple
Unicode code point compliant
const pair = Array.from('USDGBP')
pair.splice(3, 0, '/')
console.log(pair.join(''))
Given your current example you could achieve the result by either
var txt2 = txt1.split(' ').join(' bar ')
or
var txt2 = txt1.replace(' ', ' bar ');
but given that you can make such assumptions, you might as well skip directly to Gullen's example.
In a situation where you really can't make any assumptions other than character index-based, then I really would go for a substring solution.
my_string = "hello world";
my_insert = " dear";
my_insert_location = 5;
my_string = my_string.split('');
my_string.splice( my_insert_location , 0, my_insert );
my_string = my_string.join('');
https://jsfiddle.net/gaby_de_wilde/wz69nw9k/
I know this is an old thread, however, here is a really effective approach.
var tn = document.createTextNode("I am just to help")
t.insertData(10, "trying");
What's great about this is that it coerces the node content. So if this node were already on the DOM, you wouldn't need to use any query selectors or update the innerText. The changes would reflect due to its binding.
Were you to need a string, simply access the node's text content property.
tn.textContent
#=> "I am just trying to help"
You can do it easily with regexp in one line of code
const str = 'Hello RegExp!';
const index = 6;
const insert = 'Lovely ';
//'Hello RegExp!'.replace(/^(.{6})(.)/, `$1Lovely $2`);
const res = str.replace(new RegExp(`^(.{${index}})(.)`), `$1${insert}$2`);
console.log(res);
"Hello Lovely RegExp!"
Well, we can use both the substring and slice method.
String.prototype.customSplice = function (index, absIndex, string) {
return this.slice(0, index) + string+ this.slice(index + Math.abs(absIndex));
};
String.prototype.replaceString = function (index, string) {
if (index > 0)
return this.substring(0, index) + string + this.substr(index);
return string + this;
};
console.log('Hello Developers'.customSplice(6,0,'Stack ')) // Hello Stack Developers
console.log('Hello Developers'.replaceString(6,'Stack ')) //// Hello Stack Developers
The only problem of a substring method is that it won't work with a negative index. It's always take string index from 0th position.
You can use Regular Expressions with a dynamic pattern.
var text = "something";
var output = " ";
var pattern = new RegExp("^\\s{"+text.length+"}");
var output.replace(pattern,text);
outputs:
"something "
This replaces text.length of whitespace characters at the beginning of the string output.
The RegExp means ^\ - beginning of a line \s any white space character, repeated {n} times, in this case text.length. Use \\ to \ escape backslashes when building this kind of patterns out of strings.
another solution, cut the string in 2 and put a string in between.
var str = jQuery('#selector').text();
var strlength = str.length;
strf = str.substr(0 , strlength - 5);
strb = str.substr(strlength - 5 , 5);
jQuery('#selector').html(strf + 'inserted' + strb);
Using slice
You can use slice(0,index) + str + slice(index). Or you can create a method for it.
String.prototype.insertAt = function(index,str){
return this.slice(0,index) + str + this.slice(index)
}
console.log("foo bar".insertAt(4,'baz ')) //foo baz bar
Splice method for Strings
You can split() the main string and add then use normal splice()
String.prototype.splice = function(index,del,...newStrs){
let str = this.split('');
str.splice(index,del,newStrs.join('') || '');
return str.join('');
}
var txt1 = "foo baz"
//inserting single string.
console.log(txt1.splice(4,0,"bar ")); //foo bar baz
//inserting multiple strings
console.log(txt1.splice(4,0,"bar ","bar2 ")); //foo bar bar2 baz
//removing letters
console.log(txt1.splice(1,2)) //f baz
//remving and inseting atm
console.log(txt1.splice(1,2," bar")) //f bar baz
Applying splice() at multiple indexes
The method takes an array of arrays each element of array representing a single splice().
String.prototype.splice = function(index,del,...newStrs){
let str = this.split('');
str.splice(index,del,newStrs.join('') || '');
return str.join('');
}
String.prototype.mulSplice = function(arr){
str = this
let dif = 0;
arr.forEach(x => {
x[2] === x[2] || [];
x[1] === x[1] || 0;
str = str.splice(x[0] + dif,x[1],...x[2]);
dif += x[2].join('').length - x[1];
})
return str;
}
let txt = "foo bar baz"
//Replacing the 'foo' and 'bar' with 'something1' ,'another'
console.log(txt.splice(0,3,'something'))
console.log(txt.mulSplice(
[
[0,3,["something1"]],
[4,3,["another"]]
]
))
I wanted to compare the method using substring and the method using slice from Base33 and user113716 respectively, to do that I wrote some code
also have a look at this performance comparison, substring, slice
The code I used creates huge strings and inserts the string "bar " multiple times into the huge string
if (!String.prototype.splice) {
/**
* {JSDoc}
*
* The splice() method changes the content of a string by removing a range of
* characters and/or adding new characters.
*
* #this {String}
* #param {number} start Index at which to start changing the string.
* #param {number} delCount An integer indicating the number of old chars to remove.
* #param {string} newSubStr The String that is spliced in.
* #return {string} A new string with the spliced substring.
*/
String.prototype.splice = function (start, delCount, newSubStr) {
return this.slice(0, start) + newSubStr + this.slice(start + Math.abs(delCount));
};
}
String.prototype.splice = function (idx, rem, str) {
return this.slice(0, idx) + str + this.slice(idx + Math.abs(rem));
};
String.prototype.insert = function (index, string) {
if (index > 0)
return this.substring(0, index) + string + this.substring(index, this.length);
return string + this;
};
function createString(size) {
var s = ""
for (var i = 0; i < size; i++) {
s += "Some String "
}
return s
}
function testSubStringPerformance(str, times) {
for (var i = 0; i < times; i++)
str.insert(4, "bar ")
}
function testSpliceStringPerformance(str, times) {
for (var i = 0; i < times; i++)
str.splice(4, 0, "bar ")
}
function doTests(repeatMax, sSizeMax) {
n = 1000
sSize = 1000
for (var i = 1; i <= repeatMax; i++) {
var repeatTimes = n * (10 * i)
for (var j = 1; j <= sSizeMax; j++) {
var actualStringSize = sSize * (10 * j)
var s1 = createString(actualStringSize)
var s2 = createString(actualStringSize)
var start = performance.now()
testSubStringPerformance(s1, repeatTimes)
var end = performance.now()
var subStrPerf = end - start
start = performance.now()
testSpliceStringPerformance(s2, repeatTimes)
end = performance.now()
var splicePerf = end - start
console.log(
"string size =", "Some String ".length * actualStringSize, "\n",
"repeat count = ", repeatTimes, "\n",
"splice performance = ", splicePerf, "\n",
"substring performance = ", subStrPerf, "\n",
"difference = ", splicePerf - subStrPerf // + = splice is faster, - = subStr is faster
)
}
}
}
doTests(1, 100)
The general difference in performance is marginal at best and both methods work just fine (even on strings of length ~~ 12000000)
Take the solution. I have written this code in an easy format:
const insertWord = (sentence,word,index) => {
var sliceWord = word.slice(""),output = [],join; // Slicing the input word and declaring other variables
var sliceSentence = sentence.slice(""); // Slicing the input sentence into each alphabets
for (var i = 0; i < sliceSentence.length; i++)
{
if (i === index)
{ // checking if index of array === input index
for (var j = 0; j < word.length; j++)
{ // if yes we'll insert the word
output.push(sliceWord[j]); // Condition is true we are inserting the word
}
output.push(" "); // providing a single space at the end of the word
}
output.push(sliceSentence[i]); // pushing the remaining elements present in an array
}
join = output.join(""); // converting an array to string
console.log(join)
return join;
}
Prototype should be the best approach as many mentioned. Make sure that prototype comes earlier than where it is used.
String.prototype.insert = function (x, str) {
return (x > 0) ? this.substring(0, x) + str + this.substr(x) : str + this;
};