Censor words in a sentence I wrote three versions of the same code using Reduce, a functional approach and also a regex pattern approach.

I'd like to get feedback, especially from the functional one since I'm learning  functional programming and I'm sure my solution can be greatly improved.



const CHAR = 'X'
const BANNED = ['nice', 'is', 'stupid', 'potato']
const sentence = 'lorem ipsum is a nice and stupid sentence'


// VERSION 1 - REDUCE
const censor = (sentence) =&gt;
  sentence.split(' ').reduce((acc, word) =&gt;
    acc + ' ' + (BANNED.includes(word) ? CHAR.repeat(word.length) : word), '')

const censored = censor(sentence).trim()

console.log(censored)



// VERSION 2 - PIPE (functional?)
const pipe = (...fns) =&gt; fns.reduce((f, g) =&gt; (...args) =&gt; g(f(...args)))

const extractWords = (sentence) =&gt; sentence.split(' ')

const removeBanned = (arr) =&gt;
  arr.reduce((acc, word) =&gt; acc + ' ' + replaceIfBanned(word), '')

const cleanUp = (arr) =&gt; arr.trim()

const replaceIfBanned = word =&gt;
  BANNED.includes(word) ? replaceWithChar(word) : word

const replaceWithChar = (word) =&gt; CHAR.repeat(word.length)

const work = pipe(extractWords, removeBanned, cleanUp)(sentence)

console.log(work)



// VERSION 3 - REGEX
const styleHyphenFormat = (sentence) =&gt; {
  const replaceWithX = (match) =&gt; CHAR.repeat(match.length)
  const filter = new RegExp(BANNED.join('|'), 'gi')

  return sentence.replace(filter, replaceWithX)
}

console.log(styleHyphenFormat(sentence))




You can also check it out in JSFiddle.
The problem with the first two is that you are assuming separators are spaces but they could potentially be tabs, new lines or punctuation. Although it is easy to split on a non-word character joining them back in is tricky (even multiple spaces will fool the algorithm). Your regex solution has the added problem that it will convert words like kiss to kXXs.

I would stick to the regex, it is shorter and, imo, more readable. You can fix the issue by using a word boundary regex match:

const filter = new RegExp(`\\b(${BANNED.join('|')})\\b`, 'gi')


That said, I would also measure the performance of the three solutions as that is likely to be the biggest concern, especially with longer strings.

Edit 1

An alternative solution using split would be something like:

const censor = (sentence) =&gt;
  sentence.split(/\b/).map(
    (word) =&gt; BANNED.includes(word.toLowerCase()) ? CHAR.repeat(word.length) : word
  ).join('')