Search code examples
javascriptshufflemaskingscramble

How to scramble a sentence in Javascript preserving space location?


I found an script that will shuffle the string:

String.prototype.shuffle = function () {
    var a = this.split(""),
        n = a.length;

    for (var i = n - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var tmp = a[i];
        a[i] = a[j];
        a[j] = tmp;
    }
    return a.join("");
}

Using this script, following word:

What is the difference in between 'Apache Environment', 'Environment' and 'PHP Variables'?

will be shuffeled to this word on random basis:

ftewE'eim rasent  VhiEAn'oeded ta ' mb one'ennfva'nbcr?n elcttpnP iaWePh'irH rshv ieinena,

However, I am wondering how to preserve original location of each space:

ftew E' eim rasentVhiE An 'oededt a'mbone 'ennfva'nbcr? nelcttpnPiaWe Ph' irHr shvieinena,

Solution

  • One option would be to create an array of randomized characters (no spaces), then call replace on the original string with a regular expression that replaces non-space characters with an item in the array at the associated index, incrementing the index in the process:

    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(
      `What is the difference in between 'Apache Environment', 'Environment' and 'PHP Variables'?`
      .shuffle()
    );

    Also note that mutating the built-in objects like String.prototype is generally considered quite poor practice, and can break things; unless you're polyfilling something official, it would be better to use a standalone function:

    function shuffleArray(array) {
      for (let i = array.length - 1; i > 0; i--) {
        let j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
      }
      return array;
    }
    
    function shuffle(str) {
      const randomChars = shuffleArray([...str.replace(/\s+/g, '')]);
      let index = 0;
      return str.replace(/\S/g, () => randomChars[index++]);
    }
    
    console.log(shuffle(
      `What is the difference in between 'Apache Environment', 'Environment' and 'PHP Variables'?`
    ));