Can anyone explain to me how this code works?

Asked

Viewed 152 times

1

I can’t understand the use of prototype.allReplace nor the use of RegExp. What are these parameters?

String.prototype.allReplace = function(obj) {
    var retStr = this;
    for (var x in obj) {
        retStr = retStr.replace(new RegExp(x, 'g'), obj[x]);
    }
    return retStr;
};

console.log('T35t3 d3 35t4g1o'.allReplace({4: 'a', 3: 'e', 1: 'i', 5: 's'}));

There’s no simpler way to do that number-for-letter exchange?

2 answers

5

You put two questions:

  • how the code works
  • if there is no simpler way

The second question generates answers based on opinions, depends on the case, the application and the data available... so I will not answer. Regarding the first question the code works like this:

When defining a function in the prototype of a native object as "String", the this within that function will be the String.

When you have an object you have key pairs and values. For example {foo: 123} has key "foo" and value "123". So when you use var x in obj you will go through all keys of a given object, whose value is stored inside the variable x.

Thus, within this cycle/loop, with the replace the code swaps all key occurrences for the "value" of that key. Regexp’s second argument "g" means exactly "all occurrences".

At the end, after the loop returns the phrase with the exchanges made.

Take a look at this example to see in detail what happens inside the loop:

String.prototype.allReplace = function(obj) {
  let retStr = this.toString();
  for (const x in obj) {
    console.log(
      retStr,
      new RegExp(x, 'g'),
      obj[x],
      retStr.replace(new RegExp(x, 'g'), obj[x])
    );

    retStr = retStr.replace(new RegExp(x, 'g'), obj[x]);
  }
  return retStr;
};

console.log('T35t3 d3 35t4g1o'.allReplace({
  4: 'a',
  3: 'e',
  1: 'i',
  5: 's'
}));

3

To another answer already explains how the code works, so I’ll focus on your other question:

There’s no simpler way to do that number-for-letter exchange?

There are other ways to do it, but whether they are simpler or not is a matter of opinion. Anyway, let’s go to them.


Option 1: Create a single regex instead of multiple

A feature of its code is that it creates several regular expressions, one for each key of the object passed (in this case, one regex for each digit). Maybe someone thinks it’s "simpler" to create a single regex (it might be a little "better" by creating fewer things and doing everything at once, for example, but again, it’s a matter of opinion).

We can join all keys of regex in a single expression and make a single replace:

String.prototype.allReplace = function(obj) {
    let r = new RegExp(Object.keys(obj).join('|'), 'g');
    return this.replace(r, function(match) {
        return obj[match];
    });
};

console.log('T35t3 d3 35t4g1o'.allReplace({4: 'a', 3: 'e', 1: 'i', 5: 's'}));

In case, I get all the keys to obj (which in this case are the digits 4, 3, 1 and 5) and together all in a single expression: 4|3|1|5. This regex uses alternation (the character |, which means or), which means she gets any of these digits.

Then I use a function in the second parameter of replace, which in turn takes as a parameter the match (that is, the section that was found by regex). I know this excerpt can be any of the digits (4, 3, 1 or 5), so I return the corresponding value (the letters a, e, i or s, obtained from the own obj), which will be the value used in substitution.

At the end, all digits are replaced by the respective letters.

Note: if all options have only one character (in this case, all are only one digit), regex could also be [4315]. But I used toggle to make the code more "generic", so it can receive strings of various sizes. For example, if I want to trade abc for xyz:

String.prototype.allReplace = function(obj) {
    let r = new RegExp(Object.keys(obj).join('|'), 'g');
    return this.replace(r, function(match) {
        return obj[match];
    });
};

console.log('abc 123 abc'.allReplace({'abc': 'xyz'}));


Option 2: Do not use regex

It may be simpler to go through the string and replace its characters one by one, using the obj to replace the desired characters, and keeping the others:

String.prototype.allReplace = function(obj) {
    let s = '';
    for (let i = 0; i < this.length; i++) {
        let c = this.charAt(i);
        if (obj.hasOwnProperty(c)) {
            s += obj[c];
        } else {
            s += c;
        }
    }
    return s;
};

console.log('T35t3 d3 35t4g1o'.allReplace({4: 'a', 3: 'e', 1: 'i', 5: 's'}));

For each character of the string, I use hasOwnProperty to check whether obj contains a key with that character. If so, I use the respective value in the substitution, and if not, I keep the same character as the original string.

The difference to the first option is that, as I am going through the characters one by one, it is no longer possible to exchange larger excerpts (like the previous example that changes abc for xyz).


Finally, these are some alternatives to your code. Whether it is simpler or not, it goes from the opinion of each...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.