'Reverse each word with uppercase without changing word

How do I reverse each uppercase and lowercase ("I am A Great human") to ("I ma A Taerg namuh")? This is the code I Have:

function wordsReverse(str) {
    let words = [];
    words = str.match(/\S+./g);
    let result = "";
    for (let i = 0; i < words.length; i++){
        result += words[i].split('').reverse().join('') + " ";
    }
    return result;
}

console.log(wordsReverse("I am A Great human"));
// Logs "I ma A taerG namuh"

Instead of getting "I ma A taerG namuh"

I am looking for this: "I ma A Taerg namuh"



Solution 1:[1]

One way would be to track the indices of the uppercase characters in the original word, and when reversing the word use those previous index values to uppercase the character.

If the index doesn't match a previously uppercase character, then always return it as lower case (even if it is already lower case, this won't have an effect).

function wordReverse(str) {
    let reversed = [];
    let words = str.split(" ");
    for (let word of words) {
        // Calculate which indices in the word are uppercase,
        // storing in an object for faster lookups
        let uppercaseIndices = word.split("").reduce((acc, char, i) => {
            if (/[A-Z]/.test(char)) {
                acc[i] = true;
            }
            return acc;
        }, {});

        let newWord = word
            .split("")
            .reverse()
            .map((char, i) => {
                if (uppercaseIndices[i]) {
                    return char.toUpperCase();
                } else {
                    return char.toLowerCase();
                }
            })
            .join("");

        reversed.push(newWord);
    }

    return reversed.join(" ");
}

console.log(wordReverse("I am A Great human"));

Solution 2:[2]

function wordsReverse(str) {
  let indexes = [];
  let words = str.split(" ");
  let result = "";

  // reverse passed string
  words.forEach((e) => {
    result += e.split("").reverse().join("") + " ";
  });

  // get indexes of uppercase letters passed in function
  str.split("").forEach((e, i) => {
    if (e === e.toUpperCase() && e !== " ") {
      indexes.push(i);
    }
  });

  // lowercase whole string
  result = result.trim().toLowerCase().split("");

  // uppercase letters accordingly to indexes we get from index array
  result.forEach((e, i) => {
    if (indexes.includes(i)) {
      result.splice(i, 1, e.toUpperCase());
    }
  });

  return result.join("");
}

console.log(wordsReverse("I am A Great human"));

Solution 3:[3]

You can split the string into words and test each one by one with Array#map and also split each word into letters and test each letter using Array#map as in this quick demo:

const wordsReverse = str => str.split(' ').map(
    word => 
    word.split('').reverse()
    .map(
        (letter, i, arr) => 
        arr[arr.length - i - 1].toUpperCase() === arr[arr.length - i - 1] ?
        letter.toUpperCase() :
        arr[arr.length - i - 1].toLowerCase() === arr[arr.length - i - 1] ?
        letter.toLowerCase() :
        letter
    )
    .join('')
)
.join(' ');

console.log(wordsReverse("I am A Great human"));
//OUTPUT: I ma A Taerg namuh

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 romellem
Solution 2 sanodzeg
Solution 3