2

I am given two variables, a string [var str] and an array of words [var exceptions]. I am replacing every middle character of every word longer than 3 letters with an asterisk using the following regular expression:

 var edited = str.replace(/\B\w\B/g, '*');

For example, the string "This is an example of what I am doing" would be returned as "T**s is an e*****e of w**t I am d***g".

However, I would like to add exceptions to this regular expression. So for example, I am given the array (var exceptions = ["example","doing"]), then I would like the regex to return: "T**s is an example of w**t I am doing"

Does anyone know how to do this? If there is a way to achieve this using regex great, if not I am open to other suggestions.

Many thanks :)

4 Answers 4

3

You may use the exception words - I see they all consist of word chars - as an alternation group and capture it into Group 1 and then restore them inside a replace callback.

The regex will look like

/\b(example|doing)\b|\B\w\B/g

See the JS demo:

var exceptions = ["example","doing"];
var rx = new RegExp("\\b(" + exceptions.join("|") + ")\\b|\\B\\w\\B", "g");
var s = "This is an example of what I am doing";
var res = s.replace(rx, function ($0, $1) {
  return $1 ? $1 : '*';
});
console.log(res);

Pattern details:

  • \b(example|doing)\b - match a whole word example or doing and place into capturing group #1 to be restores in the result later
  • | - or
  • \B\w\B - match a word char inside other word chars (from [a-zA-Z0-9_] set).
Sign up to request clarification or add additional context in comments.

Comments

1

I'd probably turn the array of excludes into a map so that I benefit from faster checking if a word is in the array. Then I'd use the fact that the replace function accepts a function for the replacement, and make the decision in there:

var exclude = ["example", "what"];
var str = "This is an example of what I am doing";

var map = Object.create(null);
exclude.forEach(function(entry) {
  map[entry] = true;
});
var edited = str.replace(/\b(\w)(\w+)(\w)\b/g, function(m, c0, c1, c2) {
  return map[m] ? m : c0 + "*".repeat(c1.length) + c2;
});
console.log(edited);

I've used String#repeat in the above, which is from ES2015, but can be easily shimmed for older browsers. Or use c1.replace(/./g, "*") instead.


Here's an ES2015+ version, using Set rather than an object map:

let exclude = ["example", "what"];
let str = "This is an example of what I am doing";

let set = new Set();
exclude.forEach(entry => {
  set.add(entry);
});
let edited = str.replace(/\b(\w)(\w+)(\w)\b/g, (m, c0, c1, c2) =>
  set.has(m) ? m : c0 + "*".repeat(c1.length) + c2
);
console.log(edited);

Comments

1

Split the sentence in separate words with .split(" "). Then for each word, check if it is in the array of exceptions, if it is not, just add it to the newString without changes. If it is not, apply your regex.

 var newString = "";
 var exceptions = ["test"];
  "this is a test".split(" ").forEach(word =>{
       if(exceptions.includes(word))
         newString += word + " ";
       else
          newString += word.replace(/\B\w\B/g, '*') + " ";
   });

console.log(newString)

Comments

1

You could do it this way, assuming that words are always separated by spaces exclusively:

var str = "This is an example of what I am doing";
var exceptions = [ "example", "doing" ];

var edited = str.split(' ').map(function(w) {
  return exceptions.indexOf(w) != -1 ? w : w.replace(/\B\w\B/g, '*');
}).join(' ');

console.log(edited);

Comments

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.