How can I write a replace method for String in JavaScript? - javascript

I heard, that string in JavaScript has immutability.
So, how can I write a method to replace some character in string?
What I want is:
String.prototype.replaceChar(char1, char2) {
for (var i = 0; i < this.length; i++) {
if (this[i] == char1) {
this[i] = char2;
}
}
return this;
}
Then, I can use it like this:
'abc'.replaceChar('a','b'); // bbc
I know it will not work, because the immutability of string.
But in native code, I can use the native replace method like this:
'abc'.replace(/a/g,'b');
I don't really know how to solve this problem.

You can use the following approach:
String.prototype.replaceAll = function(search, replacement) {
return this.replace(new RegExp(search, 'g'), replacement);
};

You can use array, too:
String.prototype.replaceChar = function (char1, char2) {
newstr=[];
for (i = 0; i < this.length; i++) {
newstr.push(this[i]);
if (newstr[i] == char1) {
newstr[i] = char2
}
}
return newstr.join("");
}
console.log('abca'.replaceChar('a','G'));

If you want a solution without regex (as a way to learn), you can use the following:
String.prototype.replaceChar = function(char1, char2) {
var s = this.toString();
for (var i = 0; i < s.length; i++) {
if (s[i] == char1) {
s = s.slice(0, i) + char2 + s.slice(i+1);
}
}
return s;
}
console.log('aaabaaa'.replaceChar('a', 'c'))
The idea is that you need this content of the string in a temp variable, then you need to go char-by-char, and if that char is the one you are looking for - you need to build your string again.

Related

“str.fromCharCode is not a function”

Im getting the following errors:
str.fromCharCode is not a function
newStr.push is not a function
I have no clue why I’m getting those errors tbh. I might be using methods the wrong way
function rot13(str) {
var newStr = str;
for (i = 0; i < str.length; i++) {
str.fromCharCode(str[i] - 13);
newStr.push(i);
}
return newStr;
}
// Change the inputs below to test
console.log(
rot13("SERR PBQR PNZC")
)
You could try something like:
function rot13(str) {
var newStr = [];
for(i = 0; i < str.length; i++){
let x = String.fromCharCode(str[i].charCodeAt()-13);
newStr.push(x);
}
return newStr.join("");
}
It is String.fromCharCode, not myString.fromCharCode
Lastly you want charCodeAt to subtract from
Also you cannot push a char to a string. push is an Array method
function rot13(str) {
var newStr = []; // using an array - you can use += to concatenate to string
for (i = 0; i < str.length; i++) {
// I suggest you do not convert the space.
// Here I converted it to another type of space but you can use " " if you want
var x = str[i] == " " ? "\u2005":String.fromCharCode(str[i].charCodeAt(0) - 13);
newStr.push(x);
}
return newStr.join("");
}
// Change the inputs below to test
console.log(
rot13("SERR PBQR PNZC")
)

Join string based on startsWith() and endsWith()

I have string var str1 = 'foobarbaz' and var str2 = 'bazfoo'
I want to join them based on overlapping starting and ending characters. The result I am looking for is 'foobarbazfoo'.
I am currently doing it in a following way:
function merge(str1, str2) {
var size = Math.min(str1.length, str2.length);
index = 0;
for (var i = 0; i < size; i++) {
var ends = str1.substr(str1.length - i);
var starts = str2.substr(0, i);
if (ends === starts) {
index = i;
}
}
if (index === 0) {
throw 'Strings do not overlap';
} else {
return str1 + str2.substr(index, str2.length);
}
}
I wonder, if there is more elegant and efficient way of doing it ?
i think it would be a good idea to add the function to the String's prototype and using startsWith() and Conditional (ternary) Operator this what i could come up with :
String.prototype.merge = function(str) {
let match;
for (let i = this.length; i >= 0; i--)
(str.startsWith(this.slice(i))) && (match = this.slice(i));
return this.slice(0, this.indexOf(match)) + str.slice(str.indexOf(match), str.length)
}
let merged = 'foobarbaz'.merge('bazfoo')
console.log(merged);
in terms of speed, both methods are identical ( tested execution time with Performance.now() )
but less lines and a declarative rather than imperative code.
feel free to choose betwee slice and substring ( slice vs substring )

count a how many times a letter appears in javascript using indexOf

I am trying to count how many times a letter appears in a string using indexOf(). Could you advise me on where I am going wrong in my code. Thanks!
var string = 'Lets find l as many times as we can. Love is natural, love you lots';
var myFunc = function (letter) {
newString = 0;
for (var i = 0; i < letter.length; i += 1) {
if (string.indexOf('l')) {
newString += 1;
}
}
return newString;
}
Instead of this
if (string.indexOf('l')) {
newString += 1;
}
You can use charAt or even direct indexing to check each letter of a string.
Like this
if (letter[i] == 'l') {
newString += 1;
}
or this
if (letter.charAt(i) == 'l') {
newString += 1;
}
Here's a FIDDLE
Note that if you were to use indexOf you'd want to call it directly on the string in question, like this
letter.indexOf('l')
The other answer is perfectly good, but in case you really want a solution using indexOf (as the title of your question suggests), you need to provide it a second parameter, to tell it where to start looking for the next occurrence:
var myFunc = function (str) {
var i = 0, c = 0;
do {
i = str.indexOf('l', i);
} while (++i && ++c);
return c;
}
Demonstration
But, if using indexOf is not a requirement, you can simplify this to:
var myFunc = function (str) {
return str.split('l').length - 1;
}
A recursive method if you are insistent upon indexOf:
var myFunc = function (str, letter) {
var count = 0,
p = str.indexOf(letter);
if (p > -1) {
count += (1 + myFunc(str.slice(p + 1, str.length - 1), letter));
}
return count;
};
Fiddle

if array values exist in a string (similar to regex)

How can I determine if a string contains one of the values from an array?
For example:
var a = ["abc","def","ghi"];
var s = "jskljfdkljflkjk abc jskfdjklsj";
for(var i=0;i<a.length;i++){
if(/a[i]/.test(s)) alert(1);
}
This obviously doens't work... I know it's very possible though hahaha
Your syntax for creating the regular expression is incorrect. That regex will only return true for a string "ai". And you're testing the regular expression against the array. I think what you meant to write is:
if(RegExp(a[i]).test(s)) alert(1);
You would probably be better off just using indexOf in this case. It'll be faster and you won't need to escape any characters.
var a = ["abc","def","ghi"],
s = "jskljfdkljflkjk abc jskfdjklsj";
for(var i = 0, l = a.length; i < l; i++)
if(s.indexOf(a[i])+1) alert('string s contains a value from array a');
function doesStringContainElementFromArray(str, arr)
{
for ( var i=0; i<arr.length; i++)
{
if ( str.indexOf(arr[i]) != -1 )
return true;
}
return false;
}
Just use the "RegExp" function/constructor (if you really need regexps)
if (RegExp(a[i]).test(a)) {
alert(1);
}
if you don't, just use .indexOf
if (s.indexOf(a[i]) != -1) {
alert("a[i]="+a[i]+" is matched in " + s);
}
You can use search method of JavaScript
var a = ["abc","def","ghi"];
var s = "jskljfdkljflkjk abc jskfdjklsj";
for(var i=0;i<a.length;i++){
if(s.search( a[i] ) != -1)
{
alert("found");
}
}

Javascript Regex - affect only non html code? (ie text)

I have a function that wraps text with a span
$(".ui-content").html(function (i, v)
{
return v.replace(/(CANADA)/gi, '<span class="query">$1</span>');
});
However when I pass in the term "div" or "span" or "a" which are html, the page gets messed up badly of course.
What can I change the regex to remove only text that is not part of a html code like <strong> but does work on A strong person is a helpful friend
Same concept, as #elclanrs, but with an imitation of negative look behind:
$(".ui-content").html(function (i, v) {
return v.replace(/([^</])(strong)/gi, ' <span class="query">$2</span> ');
});​
http://jsfiddle.net/39VMe/
Also a good article about how to treat certain limitations of JavaScript regexp: http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript
Node manipulations to the rescue, as always!
function toArray(obj) {
var r = [];
for(var i = 0; i < obj.length; i++) {
r.push(obj[i]);
}
return r;
}
$('.ui-content').each(function() {
var stack = [this];
var c, n;
while(c = stack.pop()) {
var childNodes = toArray(c.childNodes);
for(var i = 0; n = childNodes[i]; i++) {
if(n.nodeType === 1) {
stack.push(n);
} else if(n.nodeType === 3) {
var matches = n.nodeValue.split(/(CANADA)/i);
for(var i = 0; i < matches.length; i++) {
var newNode;
if(/CANADA/i.test(matches[i])) {
newNode = document.createElement('span');
newNode.className = 'query';
newNode.appendChild(document.createTextNode(matches[i]));
} else {
newNode = document.createTextNode(matches[i]);
}
n.parentNode.insertBefore(newNode, n);
}
n.parentNode.removeChild(n);
}
}
}
});
Here's a demo jsFiddle.
I know people usually insist in not using regex for parsing html but hey this seems to work just fine. This uses a negative lookahead to replace only the word "strong" and not actual <strong> tags:
/strong(?!>)/
Edit:
Use this regex which is more flexible and allows for attributes:
/strong(?!(>|\s\w+=))/g;
In any case, it all depends on your HTML. If regex don't do it then you'll have to parse properly.
Demo: http://jsfiddle.net/mGLjb/2/

Categories

Resources