4

so I've been messing around with the .replace() function lately and wanted to make it reverse whatever the user inputs. (Aka a -> z, A -> Z, b -> y, B -> Y, ...)

I'm using function stacking, so I just added .replace().replace()... for every letter, but of course that won't work since whenever it hits n, it will begin to reverse all the progress and I end up with an inaccurate translation. Any idea how I can work around this, since as far as I know, JS doesn't have a .reverse() function like Python?

In case you need it, here's my code

//replacing letters
lettertext = ttext.replace("a", "z")
.replace("A", "Z")
.replace("b", "y")
.replace("B", "y")
.replace("c", "x")
.replace("C", "X")
.replace("d", "w")
.replace("D", "W")
.replace("e", "v")
.replace("E", "V")
.replace("f", "u")
.replace("F", "U")
.replace("g", "t")
.replace("G", "T")
.replace("h", "s")
.replace("H", "S")
.replace("i", "r")
.replace("I", "R")
.replace("j", "q")
.replace("J", "Q")
.replace("k", "p")
.replace("K", "P")
.replace("l", "o")
.replace("L", "O")
.replace("m", "n")
.replace("M", "N")
.replace("n", "m")
.replace("N", "M")
.replace("o", "l")
.replace("O", "L")
.replace("p", "k")
.replace("P", "K")
.replace("q", "j")
.replace("Q", "J")
.replace("r", "i")
.replace("R", "I")
.replace("s", "h")
.replace("S", "H")
.replace("t", "g")
.replace("T", "G")
.replace("u", "f")
.replace("U", "F")
.replace("v", "e")
.replace("V", "E")
.replace("w", "d")
.replace("W", "D")
.replace("x", "c")
.replace("X", "C")
.replace("y", "b")
.replace("Y", "B")
.replace("z", "a")
.replace("Z", "A")
.replace("ä", "ß")
.replace("Ä", "ẞ")
.replace("ö", "ü")
.replace("Ö", "Ü")
.replace("ü", "ö")
.replace("Ü", "Ö")
.replace("ß", "ä")
.replace("ẞ", "Ä")
FK82
  • 4,907
  • 4
  • 29
  • 42
Aci
  • 546
  • 5
  • 22
  • You could do something like [this](https://codereview.stackexchange.com/a/132140) – George Jan 02 '19 at 11:43
  • 2
    `"abc".split('').reverse()` do this way. – Shailesh Rathod Jan 02 '19 at 11:44
  • you can use 2 string, one you want to change and one withe characters you want to change. Then search the index of correct character and replace in your string the correct character by the new one with the same index. – Baptiste Gavalda Jan 02 '19 at 11:56
  • 1
    `JS doesn't have a .reverse() function like Python?` JS, does have a reverse, but it's not really a reverse your doing here. I'm not a Python expert, but what Python functions converts a string like `Abz` to `zYA`..? – Keith Jan 02 '19 at 12:33

8 Answers8

3

Just create an array consisting of string characters from a - z and another array consisting of all the 8 umlaut characters that you mentioned.

You can now simply create a reusable function say, reverseChar() that accepts a character as a parameter.

The function can then check if the inputted character is an alphabet or an umlaut character using a basic regex tester.

The function then tries to match the inputted character with the string characters from the respective array and if there is a match, return the same indexed character from the array reversed.


Try inputting any character from a-z, A-Z or one of the umlaut characters mentioned above in the code snippet below to see how it works:

var alpha = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];
var umlauts = ["ä","Ä","ö","Ö","ü","Ü","ß","ẞ"]

var val = "";

var result = document.getElementById("result");

function reverseChar(x) {
    
    if (/^[a-zA-Z]+$/.test(x)) {
      for (i = 0; i < 26; i++) {
          if (x.toLowerCase() == alpha[i]) {
              if (x == x.toUpperCase()) {
                val = ((alpha.reverse())[i]).toUpperCase();
              } else {
                val = (alpha.reverse())[i];
              }
          }
      }
   result.innerHTML = `The reversed character for <strong>${x}</strong> is <strong>${val}</strong>`;
    } else {
        for (i = 0; i < umlauts.length; i++) {
         if (x == umlauts[i]) {
            val = (umlauts.reverse())[i];
          }
        }
        result.innerHTML = `The reversed character for <strong>${x}</strong> is <strong>${val}</strong>`;
    }
}

// JavaScript below is for the HTML Example

var btn = document.getElementById("btn");

function checkChar(){
    var char = document.getElementById("char");
    var input = char.value;
    reverseChar(input);
}

btn.addEventListener("click", checkChar);
<input id="char" type="text" maxlength="1" />
<button type="button" id="btn">Check reversed character</button>
<p id="result"></p>
AndrewL64
  • 15,794
  • 8
  • 47
  • 79
  • 1
    +1 I like this approach, the only thing it lacks over @FK82 is the lack of support for characters such as umlauts. – JustCarty Jan 02 '19 at 13:15
  • 1
    @JustCarty I didn't notice the umlaut characters in the question earlier. I have edited the answer which adds another array for the umlaut characters too. Thanks for pointing that out mate. Cheers and a happy new year!! – AndrewL64 Jan 02 '19 at 18:06
2

You could take a hash table for the pairs and map new character or the original character if not available in the hash table.

function replace(string) {
    var code = { "a": "z", "A": "Z", "b": "y", "B": "y", "c": "x", "C": "X", "d": "w", "D": "W", "e": "v", "E": "V", "f": "u", "F": "U", "g": "t", "G": "T", "h": "s", "H": "S", "i": "r", "I": "R", "j": "q", "J": "Q", "k": "p", "K": "P", "l": "o", "L": "O", "m": "n", "M": "N", "n": "m", "N": "M", "o": "l", "O": "L", "p": "k", "P": "K", "q": "j", "Q": "J", "r": "i", "R": "I", "s": "h", "S": "H", "t": "g", "T": "G", "u": "f", "U": "F", "v": "e", "V": "E", "w": "d", "W": "D", "x": "c", "X": "C", "y": "b", "Y": "B", "z": "a", "Z": "A", "ä": "ß", "Ä": "ẞ", "ö": "ü", "Ö": "Ü", "ü": "ö", "Ü": "Ö", "ß": "ä", "ẞ": "Ä" };
    return Array.from(string, c => code[c] || c).join('');
}

console.log(replace('Übermut2019')); // 'Öyvinfg2019'
console.log(replace('Öyvinfg2019')); // 'Übermut2019'
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Thanks, it works! Just wondering, what does the `(c => code[c] || c).join("")` part do? I know it's what determines which output it exactly gives, but I don't quite get how – Aci Jan 02 '19 at 13:22
  • 2
    it uses `c` as key for a value of `code`. if this returns a [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) value, like `undefined` for a not assigned key or with a value which is falsy, then `c` is used instead. the last part just glues the array to a single string. – Nina Scholz Jan 02 '19 at 13:28
  • Ah, so technically `return Array.from(ttext, code[c]).join(``);` would also work? Where's the difference? – Aci Jan 02 '19 at 13:40
  • 1
    please watch the digits, they would be lost. – Nina Scholz Jan 02 '19 at 13:42
2

Create an object where key will be the letters of the string and its value will be the character which with you want to replace.

The on getting the input value split the string and create an array and use map and inside it's callback function check for the case of the character.

If it is lower case then directly retrieve the value, if upper case convert it to lower case to get the value from dictionary object and then convert it back to uppercase before returning.

Use join to create the final string

let rvObj = {
  a: 'z',
  b: 'y'
}

function reverse() {
  var b = document.getElementById("text")
    .value //get value of input
    .trim() // remove whitespace
    .split("") // create an array
    .map(function(a) { //map will return new array
      return a === a.toLowerCase() ? rvObj[a] : rvObj[a.toLowerCase()].toUpperCase();
    }).join(""); // create a string from the array
  console.log(b);
};
<input type="text" id='text'>
<button type='button' onclick='reverse()'>Reverse</button>
brk
  • 48,835
  • 10
  • 56
  • 78
2

Replace won't work in this case because—as you already noticed—it will not track which letters have been replaced by a prior replace operation. So, a sequence of replace operations such as

//...
.replace("M", "N")
//...
.replace("N", "M")
//...

will just undo itself (if no replacement on substrings "N" takes place in the meantime).

You can however just map over the string as an array and then work on the ASCII/UTF8 encoding of the characters to reverse the alphabetic sequence.

const s = "AzByCx";

const f = (string) => Array.from(string)
  .map(c => {
      const code = c.charCodeAt(0);

      // Leave characters `c` outside the character set [a-zA-Z] unchanged.
      if (code < 0x41 || (code > 0x5A && code < 0x61) || code > 0x7A) { 
          return c;
      }
      
      // Compute offset to last character in the set [a-z] (ASCII/UTF8: 0x41-0x5A) respectively [A-Z] (ASCII/UTF8: 0x61-0x7A)
      let offset;
      let base;
      if (code <= 0x5A) {
          offset = 0x5A - code;
          base = 0x41;
      } else {
         offset = 0x7A - code;
         base = 0x61;
      }

      // Compute new character encoding and convert back to string.
      return String.fromCharCode(base + offset)
  })
  .join('');

console.log(`${s} ~> ${f(s)}`);
console.log(`${f(s)} ~> ${f(f(s))}`);

You can extend this to include Umlauts using the same approach.

FK82
  • 4,907
  • 4
  • 29
  • 42
1

You have to switch every letter only once. You can use this pattern:

a='abcxyz'.replace(/./g,function(letter){
switch (letter) {
        case 'a':
            return 'z'
    default:
        return letter
}
})

What we doing, It will replace a to z. But it will not replace it again to a. Every letter is replaced only once.

The function I used for the replace, is executed on every letter in the string.

Aminadav Glickshtein
  • 23,232
  • 12
  • 77
  • 117
  • This doesn't seem like a great solution considering you'd have to make many switch cases? One for each letter to say the least? – JO3-W3B-D3V Jan 02 '19 at 11:51
  • You right, That why I posted another answer without the needed. In this answer, I answer to the specific issue of replacing twice the same letter after it gets replaced. – Aminadav Glickshtein Jan 02 '19 at 11:54
1

Insted of using all the replace statments, you can use the char code, to automatically find the matching pair:

a='abcxyzABC'.replace(/./g,function(letter){
if (letter>='a' && letter<='z') {
    return String.fromCharCode( 'z'.charCodeAt(0) - letter.charCodeAt(0) + 'a'.charCodeAt(0)  )
}
if (letter>='A' && letter<='Z') {
    return String.fromCharCode( 'Z'.charCodeAt(0) - letter.charCodeAt(0) + 'A'.charCodeAt(0)  )
}
})

//ouptut: 'zyxcbaZYX"
Aminadav Glickshtein
  • 23,232
  • 12
  • 77
  • 117
1

Easiest way is to use built in functions, split, reverse, and join

function reverseString(str) {

    // Step 1. Use the split() method to return a new array ["h", "e", "l", "l", "o"]
    var splitString = str.split(""); 


    // Step 2. Use the reverse() method to reverse the new created array
    // will look like ["o", "l", "l", "e", "h"]
    var reverseArray = splitString.reverse(); 

    // Step 3. Use the join() method to join all elements of the array into a string
    // will look like "olleh"
    var joinArray = reverseArray.join(""); 


    //Step 4. Return the reversed string
    return joinArray; // "olleh"
}

reverseString("hello");
Tarreq
  • 1,282
  • 9
  • 17
  • The question is about how to substitute characters in a string like for example "a~>z", not about reversing strings. The result for hello would be `"svool"` not `"olleh"`. – FK82 Jan 02 '19 at 13:08
1

There are already a lot of answers here, but it looked fun so here is my solution explained:

  1. Split the alphabet into first part & second part
  2. Reverse the second part
  3. Check every letter in which part it is and replace it by same index but reversed of the other part
  4. Add each letter to solution

EDIT: If you want to to complete sentences, also check on space :)

var alphabet = 'abcdefghijklmnopqrstuvwxyz';
var firstpart = alphabet.substring(0,13).split('');
var secondpart = alphabet.substring(13).split('').reverse();
var button = document.getElementById("button");
var solution = '';

// Click function
button.onclick = function() {
var b = document.getElementById("text").value.split('');
// Loop every letter of input
for (var i = 0 ; i < b.length; i++) {
 if (firstpart.indexOf(b[i]) !== -1) {
   solution += secondpart[firstpart.indexOf(b[i])];
 } else {
   solution += firstpart[secondpart.indexOf(b[i])];
  }
}
console.log(solution);
// Reset solution
solution = '';
}
<input type="text" id='text'>
<button type='button'id='button'>Reverse</button>
Wimanicesir
  • 4,606
  • 2
  • 11
  • 30