0

Below is a custom String method from How do I replace a character at a particular index in JavaScript?

String.prototype.replaceAt = function(index, replacement) {
    return this.substring(0, index) + replacement + this.substring(index + replacement.length);
}

I didn't want the replacement to replace the proceeding characters so I changed it to

String.prototype.replaceAt = function(index, replacement) {
    return this.substring(0, index) + replacement + this.substring(index);
}

I was using this to replace the '#' with a '%23' because otherwise the browser doesn't understand the link at gives a 404 error (I am programming this on a localhost server). My fileNames array looks like

const fileNames = [
    ["template.html", "first.php", "second.php", "comments.php", "predefined.php", "strings.php", "concat.php", 
    "numbers.php", "constants.php", "quotes.php"],
    ["form.html", "handle_form #1.php", "handle_form #2.php", "handle_form #3.php"],
    [""],
    [""],
    [],
    [],
];

Then I loop through the 2-D array. Finally, I loop through each string in fileNames with another loop. If the following code is commented out it works fine but the task that the code accomplishes is not carried out.

        for (let k = 0; k < fileNames[i][j].length; k++) {
            if (fileNames[i][j][k] == '#') {
                fileNames[i][j] = fileNames[i][j].replaceAt(k, '%23');
            }
        }
    }
}

The problem is as soon as I change index + replacement.length to index, the page stops loading and a popup shows up saying the page is unresponsive. Why is this happening? How do I fix it? Unresponsive page

Marvin
  • 853
  • 2
  • 14
  • 38
  • Could you clarify the problem with the original solution you found? – Solomon Ucko Oct 30 '18 at 23:04
  • "The problem is as soon as I change index + replacement.length to index, the page stops loading and a popup shows up saying the page is unresponsive." – Marvin Oct 31 '18 at 00:54
  • Sorry for being unclear. I was referring to the reason for changing it. – Solomon Ucko Oct 31 '18 at 01:01
  • Oh, the reason for changing it was that these are links. In the URL, it doesn't automatically encode "#" to be "%23" so I had to do it myself. Either way it would return a **404**. For example, in *handle_form #1.php* it had to change to *handle_form%20%231.php* otherwise it would have changed to *handle_form%20%23php*.I don't want it to replace the '1' and '.' – Marvin Nov 01 '18 at 02:41
  • I see, that makes sense. Sorry. – Solomon Ucko Nov 01 '18 at 10:25
  • @Solomon Ucko No problem! – Marvin Nov 11 '18 at 17:53

4 Answers4

1

The code is causing an infinite loop because your faulty version of replaceAt is merely inserting the desired substring before each # character. This means that the code, as it processes through the string, will always find another # a few characters further on, and thus the loop becomes infinite and blocks the browser.

I believe you mean to use this instead:

String.prototype.replaceAt = function(index, replacement) {
    return this.substring(0, index) + replacement + this.substring(index + 1);
}

(Note the + 1 - that's the only change!)

Robin Zigmond
  • 17,805
  • 2
  • 23
  • 34
1

Your current logic is merely moving the # farther up the string, resulting in an infinite loop:

String.prototype.replaceAt = function(index, replacement) {
    return this.substring(0, index) + replacement + this.substring(index);
}
console.log('foo#bar'.replaceAt(3, 'baz'));

Instead of a custom replace function though, why not just use the built-in .replace? Use a global regular expression to match #s, and replace with '%23'. For example:

const fileNames = [
    ["template.html", "first.php", "second.php", "comments.php", "predefined.php", "strings.php", "concat.php", 
    "numbers.php", "constants.php", "quotes.php"],
    ["form.html", "handle_form #1.php", "handle_form #2.php", "handle_form #3.php"],
    [""],
    [""],
    [],
    [],
];
const fixedFileNames = fileNames.map((arr) => (
  arr.map((str) => str.replace(/#/g, '%23'))
));
console.log(fixedFileNames);

Array methods are generally a lot nicer to work with than for loops - no manual iteration, better abstraction.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Thank you, CertainPerformance, for the answer! I didn't do it like this because there were other tasks being done in the nested for loop. This needed to be put exactly in between them. – Marvin Oct 30 '18 at 22:54
  • If it's string manipulation, you can *probably* do it with a regular expression - regex is an extremely powerful and concise tool in the right situation. – CertainPerformance Oct 30 '18 at 23:20
  • I agree that regular expressions are extremely powerful, evidently https://stackoverflow.com/questions/51996320/why-is-the-function-being-called-multiple-times-in-a-loop/51996673#51996673 at the answer to my question here. How about I make a JSFiddle and you can see my code and goal in context to see if there _is_ a way? – Marvin Oct 31 '18 at 00:59
  • Sure, I'll be happy to look at it – CertainPerformance Oct 31 '18 at 01:00
0

Hmm, not a huge fan of changing the string prototype like that.

If your aim is to encode the hash character, why not use:

encodeURIComponent("#")

Output: "%23"

David Kiff
  • 1,200
  • 2
  • 11
  • 24
0

Couple general things, then the solution.

  1. You should your browser's developer tools to see what the actual error is, and post that as well.
  2. It's generally frowned upon to tack things onto the in-built object types. I recommend using a standalone function.

Actual solution: the code you posted is an insertion, not a replacement: it leaves in the hash. Then, because you are leaving it it, the loop "finds" it again and runs forever. Try this:

String.prototype.replaceAt = function(index, replacement) {
    return this.substring(0, index) + replacement + this.substring(index + numberOfCharsToOmit);
}

And add in a number appropriately.

Andrew Ridgway
  • 574
  • 2
  • 9
  • Thanks for the answer, Andrew Ridgway! In my opinion, it is debatable whether to use global functions or add methods to built-in object types. This is also local, and I am using it to organize my PHP files, which I am coding from a book that teaches me how to program in php and mysql. It will never go on GitHub, public viewing, or use other libraries (I like pure JavaScript). Also, because the page wasn't loading, I could not see an error. I tried console.log and it seemed fine until I actually executed it in the return statement. – Marvin Oct 30 '18 at 22:47