Search code examples
javascriptstringcharacterscramble

JavaScript - How do I shuffle the characters in a string skipping certain character(S)


I'm a javascript beginner and I got stuck having a problem. I have a javascript's function to shuffle the characters in a string in that way that words length and spaces are kept like in original sentence.

function shuffleArray(array) {
  for (let i = array.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
  return array;
}

String.prototype.shuffle = function () {
  // pass to shuffleArray an array of all non-whitespace characters:
  const randomChars = shuffleArray([...this.replace(/\s+/g, '')]);
  let index = 0;
  // `\S` matches any non-whitespace character:
  return this.replace(/\S/g, () => randomChars[index++]);
}

console.log(
  `The keys are under the mat`
  .shuffle()
);

What I want to add is adding to the function a variable with defined letters which should be skipping in shuffle process. Now we have, i.e:

  • original string:

The keys are under the mat

  • now shuffled string looks like:

atd meey eke nTshr hau ert

  • and what I want: I want to define characters e.g: [hr] and those letters should stay "frozen" in their positions and not be processed by shuffle function:

final result:

ahd meey ere nTshr ahu ekt


Solution

  • I believe this code does what you are looking for:

    function shuffleString(string, fixed) {
        let result = '';
        const allChars = Array.from(string);
        const fixedChars = Array.from(fixed); 
        fixedChars.push(" "); // Consider the blank space as a fixed character, as you wish to maintain the separation on the string
        const singleChars = Array.from(string).filter(char => !fixedChars.includes(char));
    
        allChars.forEach((char) => { 
            if (fixedChars.includes(char)) { // If the sting is fixed, just add it
                result += char;
            } else { // If string is not fixed, get a random one
                const randomPosition = Math.floor(Math.random() * (singleChars.length));
                result += singleChars[randomPosition];
                singleChars.splice(randomPosition, 1); // Remove from the options array, since it should not be selected more than once
            }
        });
        
        return result;
    }
    
    console.log(shuffleString('this is a test', 'et'));

    It is O(n), n being the number of letters in the text. Hope it helps!