3

I want to replace a bad word with asterisks ***. However, there is a problem when the bad word is contained in an another word I don't want to replace it.

for(var i = 0; i < forbidden.length; i++) {
    if(textBoxValue.search(forbidden[i]) > -1) {
        textBoxValue = textBoxValue.replace(forbidden[i], '');
    }
}

For example if the bad word is "are", if it is in another word like "aren't" I don't want it to appear as "***n't". I only want to replace the word if it is by itself.

Dale K
  • 25,246
  • 15
  • 42
  • 71
cosette
  • 33
  • 7

3 Answers3

4

One option is to use a regular expression with a word boundary on each side, to ensure that a matched word is standalone:

forbidden.forEach((word) => {
  textBoxValue = textBoxValue.replace(new RegExp('\\b' + word + '\\b', 'g'), '');
});

For example:

let textBoxValue = 'bigwordfoo foo bar barbaz';
const forbidden = ['foo', 'bar'];

forbidden.forEach((word) => {
  textBoxValue = textBoxValue.replace(new RegExp('\\b' + word + '\\b', 'g'), '');
});
console.log(textBoxValue);

If you actually want to replace with asterisks, and not the empty string, use a replacer function instead:

let textBoxValue = 'bigwordfoo foo bar barbaz';
const forbidden = ['foo', 'bar'];

forbidden.forEach((word) => {
  textBoxValue = textBoxValue.replace(
    new RegExp('\\b' + word + '\\b', 'g'),
    word => '*'.repeat(word.length)
  );
});
console.log(textBoxValue);

Of course, note that word restrictions are generally pretty easy to overcome by anyone who really wants to. Humans can almost always come up with ways to fool heuristics.

If any of the words to blacklist contain special characters in a regular expression, escape them first before passing to new RegExp:

const escape = s => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');

let textBoxValue = 'bigwordfoo foo ba$r ba$rbaz';
const forbidden = ['foo', 'ba$r'];

forbidden.forEach((word) => {
  textBoxValue = textBoxValue.replace(
    new RegExp('\\b' + escape(word) + '\\b', 'g'),
    word => '*'.repeat(word.length)
  );
});
console.log(textBoxValue);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • instead of replacing in a loop you could build a regex that matches all words `'\\b(?:' + forbidden.map(escape).join('|') + ')\\b'` – Thomas Jun 07 '19 at 09:27
3

You can create a dynamic regex with all the forbidden words separated by a | to create an alternation. You can wrap this with word boundary (\b) to replace only full word matches.

For the following list of forbidden words, the dynamic regex ends up being

/\b(?:bad|nasty|dreadful)\b/g

The second parameter to replace, gets the matched word as a parameter. You can use repeat to get * repeated the same number of times as the length of the word to be replaced

function replaceBadWords(textBoxValue, forbidden) {
  const regex = new RegExp(`\\b(?:${forbidden.join('|')})\\b`, 'g')
  return textBoxValue.replace(regex, m => "*".repeat(m.length))
}

const forbidden = ['bad', 'nasty', 'dreadful']

console.log(replaceBadWords('string with some nasty words in it', forbidden))
console.log(replaceBadWords("bad gets replaced with asterisks but badminton won't", forbidden))
adiga
  • 34,372
  • 9
  • 61
  • 83
3

If you're not yet using a library (Or if you want to use one)

You can check this repo out.

First, they already have a list of bad words so you don't need to think about them and think what you missed.

They support placeholders like:

var Filter = require('bad-words');
var customFilter = new Filter({ placeHolder: 'x'});

customFilter.clean('Don't be an ash0le'); //Don't be an xxxxxx

and you can add your own bad words like or remove it:

var filter = new Filter(); 

// add to list
filter.addWords('some', 'bad', 'word');

// remove from list
filter.removeWords('hells', 'sadist');

And also a multi lingual support if you have the correct regex.

I am L
  • 4,288
  • 6
  • 32
  • 49