2
\$\begingroup\$

I am doing some exercises in this book. I've been trying to avoid Regex so far in my mission to teach myself computer science, as it makes my head hurt. That said - one of the exercises is to find all words without the letter 'e'.

I have:

/\b([^e ]+)\b/

There must be a better way using Regex to find all words that don't contain a certain character.

Here is an example:

toMatch = /\b([^e ]+)\b/;
testArr = ["platypus", "elvis", "javascript", "stackoverflow"];

for (str in testArr)
  console.log(testArr[str] + " has no e -> " + toMatch.test(testArr[str]));

\$\endgroup\$
1
  • 2
    \$\begingroup\$ for...in should not be used to iterate over an array. \$\endgroup\$
    – Kruga
    Commented Dec 19, 2016 at 8:50

4 Answers 4

4
\$\begingroup\$

While using regex, yours is probably the most simple. Just make sure you set the g flag in other languages:

https://regex101.com/r/zJ0H2k/2

If you know about regex in unnecessary complexity you can use look behinds and such:

/(?:^|(?<= ))([^e ]+)(?:\n|(?= )|$)/g

https://regex101.com/r/cM9hD8/1

you can make your regex as complicated as possible, I think that your answer is a good answer just in terms of the length of the regular expression.

\$\endgroup\$
6
\$\begingroup\$

If just looking for a single character in a set of strings, I would think basic string manipulation would be sufficient.

What is not clear to me from your question is why you are using word boundaries in your regex definition when the array itself is just single words. Is your intent to analyze individual words in each of the array strings (with string perhaps consisting of multiple words) or are you only truly going to have single word string in the array?

For now, I will provide answer given the assumption of an array of single words.

To do that, I would simply use Array.filter() in combination with String.indexOf().

var needle = 'e';
var haystack = ["platypus", "elvis", "javascript", "stackoverflow"];
var filtered = haystack.filter( str => (str.indexOf(needle) === -1) );

Based on your comment that array entries could have multiple words, I would suggest using Array.reduce() to build all array of all words across all entries that do not have have the needle character in them.

var needle = 'e';
// note global flag here to get all matches
var regex = new RegExp('\\b([^' + needle + ']+)\\b', 'g');
var haystack = ["platypus", "elvis", "javascript", "stackoverflow", "some multi-word string"];
var result = haystack.reduce(
    (aggregator, str) => {
        while (match = regex.exec(str) !== null) {
            aggregator.push(match[1]);
        }
    },
    []
);
console.log(result); // ["platypus", "javascript", "multi-word", "string"]
\$\endgroup\$
2
  • \$\begingroup\$ Hi Mike, thanks for your answer. I am trying specifically to do this in regex (from eloquentjavascript.net/09_regexp.html). In answer to your question; the examples given in the book have arrays with multi-word elements. \$\endgroup\$
    – Aidenhjj
    Commented Dec 16, 2016 at 17:54
  • \$\begingroup\$ @Aidenhjj I have updated my answer to consider search within multi-word strings in the array. \$\endgroup\$
    – Mike Brant
    Commented Dec 16, 2016 at 18:34
6
\$\begingroup\$

I tried

/\b[^e]+\b/i

for the first time too, but the problem with it, is that it also returns true to inputs such as "444fortyfortyfour", where there are digits in the word.

The book says:

  1. A word without the letter e (or E)

I had come up with the following solution:

let regExp = /\b[a-df-z]+\b/i

regExp.test("Anything")
// true

regExp.test("Except 'e'")
// false

regExp.test("0r th1s")
// false

It does not look like a nice solution, but it does the job. I am interested in a more elegant solution though.

PS: don't forget to add the letter 'i' for case insensivity!

\$\endgroup\$
1
\$\begingroup\$
/\b[^\We]+\b/g
  • \W means NOT a "word" character.
  • ^\W means a "word" character.
  • [^\We] means a "word" character, but not an "e".

see it in action: word without e

"and" Operator for Regular Expressions

BTW, I think this pattern can be used as an "and" operator for regular expressions.

In general, if:

  • A = not a
  • B = not b

then:

[^AB] = not(A or B) 
      = not(A) and not(B) 
      = a and b

Difference Set

So, if we want to implement the concept of difference set in regular expressions, we could do this:

a - b = a and not(b)
      = a and B
      = [^Ab]
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Hello, and welcome to Code Review. Code dumps without an explanation of why the code is an improvement on the OP's code, are not good Code Review answers. Please explain why this Regex is an improvement on the OP's. \$\endgroup\$
    – rolfl
    Commented May 5, 2021 at 3:41
  • \$\begingroup\$ @rolfl explanation was added. I thought it was obvious for anyone who knows regex well to understand it. \$\endgroup\$
    – lochiwei
    Commented May 5, 2021 at 4:29
  • \$\begingroup\$ The point of the Code Review Community is to help people improve their coding skills by making at least one insightful observation about the code. Code only alternate solutions doesn't help anyone improve their code. \$\endgroup\$
    – pacmaninbw
    Commented May 5, 2021 at 12:46

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.