1

I'm trying to replace random strings characters with a a set amount of a specific character (i.e: "*"), I'll explain more in the code below.

/**
 * Returns a string with replaced amount of strings with a set string
 * @param {string} str The input
 * @param {number} amountToReplace The amount of letters you want to replace
 * @param {string} generalReplace The general letter to replace with
 * @returns {string} Returns a string with the string thats finished
 */

var str = 'thisisastring';
var amountToReplace = 5; 
var generalReplace = '*'

// Function over here, e.g. with the name replacer
var returnMe = replacer(str, amountToReplac

Sorry if the params sound confusing, I'm still new to them!!

So the string, str is the string that's the input the amountToReplace is the amount of letters you want to replace and the generalReplace is general character you want to replace with.

If the amount is 5, the output I'm expecting is something like:

original: thisisastring
output: th*s**as*ri*g

The string that is returned is supposed to replace random parts in the string(but still do the amount that was inputted, instead of doing 5 replacers but returning 3 as common matches were found).

Thanks!

2
  • You want random replacement? Commented Sep 21, 2021 at 1:50
  • Yes, but also with a set amount of strings I want to replace with Commented Sep 21, 2021 at 1:51

4 Answers 4

2

The smallest (arguably simplest):

  • Split the string into Array [...str] // (is now an Array)
  • Loop inserting at random points an array with the replacer character like i.e: ["t", "h", "i", ["*"], "i", ["*"], ...
  • continue looping until i (the amount) is not 0 and until the current value at the iterating index is an Array.
  • Once all done, since we have how a 2D array, use Array.prototype.flat() to make it one dimensional like i.e: ["t", "h", "i", "*", "i", "*", ...
  • and convert it back to String using Array.prototype.join()

const replacer = (str, i, rep) => {
  if (!str) return;                      // Do nothing if no string passed
  const arr = [...str];                  // Convert String to Array
  const len = arr.length
  i = Math.min(Math.abs(i), len);        // Fix to Positive and not > len 
  while (i) {
    const r = ~~(Math.random() * len);
    if (Array.isArray(arr[r])) continue; // Skip if is array (not a character)
    arr[r] = [rep];                      // Insert an Array with the rep char
    --i;
  }
  return arr.flat().join("");
};


console.log(replacer("thisisastring", 5, "*"));

The above example is battle-tested and works amazingly even if:

  • There's no string or it's empty
  • The string contains already all asterisks "*****"
  • The amount is greater then the string length
  • The amount is a negative integer

The longest:

  • Generate an Array of N (amountToReplace) random unique integers
  • Convert the input string to Array, iterate it replacing every character in that random index to the generalReplace "*" character

/**
 * Create an array of unique integers
 * @param {Integer} len Array length
 * @param {Integer} max Max integer value
 * @returns {Array} Array of random Unique integers
 */
function genArrRandInt(len, max) {
  const nums = new Set();
  while (nums.size !== len) nums.add(Math.floor(Math.random() * max));
  return [...nums];
};

/**
 * Returns a string with replaced amount of strings with a set string
 * @param {string} str The input
 * @param {number} amountToReplace The amount of letters you want to replace
 * @param {string} generalReplace The general letter to replace with
 * @returns {string} Returns a string with the string thats finished
 */
function replacer(str, amountToReplace, generalReplace) {
  const strArr = [...str];
  const uniqueArr = genArrRandInt(amountToReplace, str.length);
  uniqueArr.forEach(i => strArr[i] = generalReplace);
  return strArr.join("");
}


const str = "thisisastring";
const amountToReplace = 5;
const generalReplace = "*";

// Function over here, e.g. with the name replacer
const returnMe = replacer(str, amountToReplace, generalReplace);
console.log(returnMe);

Sign up to request clarification or add additional context in comments.

6 Comments

Thank you so much for being so detailed, params were extremely useful and descriptive, amazing in-depth answer!
@Jeffplays2005 you're welcome
@Jeffplays2005 there's another fix you could do in genArrRandInt(len, max) and that's to use max = Math.min(len, max); to prevent max being greater than the the string length - in case you used something like : replacer("aaa", 5, "*") since "aaa" is smaller in length than 5. Or you could do the same inside the replacer function.
I just wanted to mention, there was a really small minor mistake for the first example, instead of return res.flat().join("");, it would be return arr.flat().join(""); as res is undefined!
@Jeffplays2005 thank you so much for the extra eye. Thought arr would be a better term than res and forgot to rename the latest one :D thank you
|
1

Code might be something like:

function rand(min, max){
  let mn = min, mx = max;
  if(mx === undefined){
    mx = mn; mn = 0;
  }
  return mn+Math.floor(Math.random()*(mx-mn+1));
}
function randCharReplace(string, replaceWith = '*', replaceCount = 1){
  const a = string.split(''), m = a.length-1;
  const f = ()=>{
    return rand(0, m);
  }
  for(let i=0,r; i<replaceCount; i++){
    while(r === undefined || a[r] === replaceWith){
      r = f();
    }
    a[r] = replaceWith;
  }
  return a.join('');
}
console.log(randCharReplace('thisisastring',  '*', 5));

Comments

1

A better efficient approach using Set

function replacer(str, len = 0, generalReplacer) {
  const length = len > str.length ? str.length : len,
           set = new Set(),
           newStr = [];
  
  while (set.size !== length) {
    set.add(Math.floor(Math.random() * str.length));
  }

  for (let i = 0; i < str.length; ++i) {
    set.has(i) ? newStr.push(generalReplacer) : newStr.push(str[i]);
  }

  return newStr.join("");
}

console.log(replacer("thisisastring", 5, "*"));
console.log(replacer("thisisastring", 1, "*"));
console.log(replacer("thisisastring", 7, "*"));

1 Comment

newStr.push("*") should be newStr.push(generalReplacer)
0

function replacer(string, amount) {
    // If string contains all '*' return string
    if ([...string.matchAll(/\*/g)].length === string.length) {
        return string
    }
    // copy the ori string convert to array
    let res = [...string]
    let i = amount
    let e = ['*', ' ']
    // iterate amount times
    while (i >= 1) {
        // get random index in array
        const randomIdx = Math.floor(Math.random() * string.length)
        // get char at index
        const randomChar = res[randomIdx]
        // check if it not '*' or ' '
        if (!e.includes(randomChar)) {
            // replace char with '*'
            res.splice(randomIdx, 1, '*')
            i--
        }
    }
    return res.join('')
}

You can try this.

2 Comments

replacer("asdf", 3) returns wrong results like asd*, a*s* instead of i.e: *s** and if the string is replacer("***", 3) we enter an infinite loop.
@RokoC.Buljan Thanks you for pointing out the err. I edited my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.