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

95 views Asked by At

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

3

There are 3 answers

0
user214762 On BEST ANSWER

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!

0
Spix737 On

The best solution I can come up with is the following:

  1. Store all the letters you won't be replacing in an array.
  2. Iterate over the original string, replacing each character with a random character from the array as long as the character you're replacing isn't (in your case) either: ['h','r'].

There's a lot of ways to go about this, but making it efficient depends on a bunch of factors, such as the specific input string, it's length and the number of characters in your exclusion array.

I'd look into using the .split() method, demonstrated here: w3schools .split()

Hope this helps.

1
Nina Scholz On

You could take a string of characters who remain and build two regular expression for collection and replacing.

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

String.prototype.shuffle = function (keep = '') {
    keep += '\\s';
    const
        chars = this.replace(new RegExp(`[${keep}]`, 'gi'), ''),
        randomChars = shuffleArray([...chars]);
   
    let index = 0;
    return this.replace(new RegExp(`[^${keep}]`, 'gi'), () => randomChars[index++]);
};

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