Valid output in IE9 but undefined output in IE7/IE8 - javascript

I wrote a simple 'replaceAll' function that extends String.prototype.
String.prototype.replaceAll = function (removalChar, insertionChar) {
var output = "";
for (var i = 0; i < this.length; i++) {
if(this[i] == removalChar) {
output += insertionChar;
}
else {
output += this[i];
}
}
return output;
}
Test code:
var test = "Hello-1-2-3";
alert(test.replaceAll("-"," "));
My test code alerts Hello 1 2 3 in all browsers including IE9.
But in IE7 and 8, the output I get is something like this: undefinedundefinedundefinedundefinedundefinedundefined...
jsFiddle: http://jsfiddle.net/cd4Z2/
(try this in IE7/IE8)
How could I possibly rewrite the function to ensure it works on IE7/8 without breaking its behaviour on other browsers?

You can't access string chars with this[i] in IE7/8. Use .charAt(i) instead, as explained here:
Javascript strings - getting the char at a certain point
Updated fiddle (tested in IE8): http://jsfiddle.net/cd4Z2/2/
I've just replaced this[i] with this.charAt(i).
In this question, some good reasons are stated on why you'd prefer to use charAt as opposed to string[index]. The latter is not part of ECMAScript 3.

IE<9 don't treat a string like an array, i.e. they lack ability to refer individual letter with index. You can use a temporary array (var temp = this.split('');) instead of this[i]

Try this out:-
String.prototype.replaceAll = function (removalChar, insertionChar) {
var output = "";
var res = this.split('');
for (var i = 0; i < this.length; i++) {
if(res[i] == removalChar) {
output += insertionChar;
}
else {
output += res[i];
}
}
return output;
}
var test = "Hello-1-2-3";
//alert(test.replace("-"," "));
alert(test.replaceAll("-"," "));

Related

How to replace all same charter/string in text with different outcomes?

For example let's say I want to attach the index number of each 's' in a string to the 's's.
var str = "This is a simple string to test regex.";
var rm = str.match(/s/g);
for (let i = 0;i < rm.length ;i++) {
str = str.replace(rm[i],rm[i]+i);
}
console.log(str);
Output: This43210 is a simple string to test regex.
Expected output: This0 is1 a s2imple s3tring to tes4t regex.
I'd suggest, using replace():
let i = 0,
str = "This is a simple string to test regex.",
// result holds the resulting string after modification
// by String.prototype.replace(); here we use the
// anonymous callback function, with Arrow function
// syntax, and return the match (the 's' character)
// along with the index of that found character:
result = str.replace(/s/g, (match) => {
return match + i++;
});
console.log(result);
Corrected the code with the suggestion — in comments — from Ezra.
References:
Arrow functions.
"Regular expressions," from MDN.
String.prototype.replace().
For something like this, I would personally go with the split and test method. For example:
var str = "This is a simple string to test regex.";
var split = str.split(""); //Split out every char
var recombinedStr = "";
var count = 0;
for(let i = 0; i < split.length; i++) {
if(split[i] == "s") {
recombinedStr += split[i] + count;
count++;
} else {
recombinedStr += split[i];
}
}
console.log(recombinedStr);
A bit clunky, but works. It forgoes using regex statements though, so probably not exactly what you're looking for.

Object Oriented Javascript Chapter 4 Exercise 4

Hi all I'm learning Javascript with the Stoyan Stefanov's book. I'm stuck on Chapter 4 Exercise 4:
Imagine the String()constructor didn't exist. Create a constructor
function MyString()that acts like String()as closely as possible.
You're not allowed to use any built-in string methods or properties,
and remember that String()doesn't exist. You can use this code to
test your constructor:
>>> var s = new MyString('hello');
>>> s[0];
"h"
I can't think on a way to achieve "s[0]", at least not with the knowledge I have now.
Any thoughts?
Thanks
Objects can have properties of themselves defined using array like syntax. String chars can be accessed with array like syntax.
function MyString (str) {
this.length = 0; // string length
var i = 0;
while(str[i] != undefined) {
this.length++;
i++;
}
for (var i=0; i< this.length;i++)
{
this[i]=str[i];
}
}
var s=new MyString('hello');
alert(s[0]); //h
here is my solution for this exercice :
function MyString(msg){
var array_msg = msg.split("");
array_msg.toString = function(){
return array_msg.join("");
};
array_msg.valueOf = function(){
return array_msg.toString();
};
array_msg.charAt = function(i){
if(array_msg[i] === undefined){
return array_msg[0];
}else{return array_msg[i];}
};
array_msg.concat = function(msg2){
return array_msg.join("")+" "+msg2;
};
array_msg.slice = function(d,f){
var res = "";
if(f<0){
f = array_msg.length + f;
}
for(var i=d; i<f; i++){
res += array_msg[i]
}
return res;
};
array_msg.split = function(el){
return array_msg.toString().split(el);
};
return array_msg;
}
A slight variation of the above...more of a tweak than anything
var MyString = function (s) {
for (var i = 0; i < s.length; i++){
this[i] = s[i]
}
this.length = function() .....
You also don't need to assign it to anything as extra as the comment suggests. this[i] will be created for the length of the string passed to s
EDIT:
Part of the question in the book says not to use existing string methods so can't use charAt so I've switched it to s[I]
This is another variation of one of the above solutions but instead of using a for loop I am using a while loop. I don't usually use while loops for these kinds of things but it worked really well here.
Adding the length property is optional.
function MyString(str) {
this.length = 0; // Creating an optional length property
this.value = str;
var i = 0;
while(str[i] != undefined) {
this[i] = str[i];
this.length++;
i++;
}
}
var name = new MyString('billy');
console.log(name.value); // 'billy'
console.log(name[0]); // 'b'
console.log(name.length); // 5

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");
}
}

Multiple specials characters replacement optimization

I need to replace all the specials characters in a string with javascript or jQuery.
I am sure there is a better way to do this.
But I currently have no clue.
Anyone got an idea?
function Unaccent(str) {
var norm = new Array('À','Á','Â','Ã','Ä','Å','Æ','Ç','È','É','Ê','Ë','Ì','Í','Î','Ï', 'Ð','Ñ','Ò','Ó','Ô','Õ','Ö','Ø','Ù','Ú','Û','Ü','Ý','Þ','ß', 'à','á','â','ã','ä','å','æ','ç','è','é','ê','ë','ì','í','î','ï','ð','ñ', 'ò','ó','ô','õ','ö','ø','ù','ú','û','ü','ý','ý','þ','ÿ');
var spec = new Array('A','A','A','A','A','A','A','C','E','E','E','E','I','I','I','I', 'D','N','O','O','O','0','O','O','U','U','U','U','Y','b','s', 'a','a','a','a','a','a','a','c','e','e','e','e','i','i','i','i','d','n', 'o','o','o','o','o','o','u','u','u','u','y','y','b','y');
for (var i = 0; i < spec.length; i++) {
str = replaceAll(str, norm[i], spec[i]);
}
return str;
}
function replaceAll(str, search, repl) {
while (str.indexOf(search) != -1) {
str = str.replace(search, repl);
}
return str;
}
Here's a version using a lookup map that works a little more efficiently than nested loops:
function Unaccent(str) {
var map = Unaccent.map; // shortcut
var result = "", srcChar, replaceChar;
for (var i = 0, len = str.length; i < len; i++) {
srcChar = str.charAt(i);
// use hasOwnProperty so we never conflict with any
// methods/properties added to the Object prototype
if (map.hasOwnProperty(srcChar)) {
replaceChar = map[srcChar]
} else {
replaceChar = srcChar;
}
result += replaceChar;
}
return(result);
}
// assign this here so it is only created once
Unaccent.map = {'À':'A','Á':'A','Â':'A'}; // you fill in the rest of the map
Working demo: http://jsfiddle.net/jfriend00/rRpcy/
FYI, a Google search for "accent folding" returns many other implementations (many similar, but also some using regex).
Here's a bit higher performance version (2.5x faster) that can do a direct indexed lookup of the accented characters rather than having to do an object lookup:
function Unaccent(str) {
var result = "", code, lookup, replaceChar;
for (var i = 0, len = str.length; i < len; i++) {
replaceChar = str.charAt(i);
code = str.charCodeAt(i);
// see if code is in our map
if (code >= 192 && code <= 255) {
lookup = Unaccent.map.charAt(code - 192);
if (lookup !== ' ') {
replaceChar = lookup;
}
}
result += replaceChar;
}
return(result);
}
// covers chars from 192-255
// blank means no mapping for that char
Unaccent.map = "AAAAAAACEEEEIIIIDNOOOOO OUUUUY aaaaaaaceeeeiiiionooooo uuuuy y";
Working demo: http://jsfiddle.net/jfriend00/Jxr9u/
In this jsperf, the string lookup version (the 2nd example) is about 2.5x faster.
Using an object as a map is a good idea, but given the number of characters you're replacing, it's probably a good idea to pre-initialize the object so that it doesn't have to be re-initialized each time the function gets run (assuming you're running the function more than once):
var Unaccent = (function () {
var charMap = {'À':'A','Á':'A','Â':'A','Ã':'A','Ä':'A' /** etc. **/};
return function (str) {
var i, modified = "", cur;
for(i = 0; i < str.length; i++) {
cur = str.charAt(i);
modified += (charMap[cur] || cur);
}
return modified;
};
}());
This will front-load the heavy lifting of the function to page load time (you can do some modifications to delay it until the first call to the function if you like). But it will take some of the processing time out of the actual function call.
It's possible some browsers will actually optimize this part anyway, so you might not see a benefit. But on older browsers (where performance is of greater concern), you'll probably see some benefit to pre-processing your character map.
You can prepare key value pair type of array and via jquery each traverse that array.
Example :
function Unaccent(str) {
var replaceString = {'À':'A','Á':'A','Â':'A'}; // add more
$.each(replaceString, function(k, v) {
var regX = new RegExp(k, 'g');
str = str.replace(regX,v);
});
}
Working Demo
Good Luck !!

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