0

I'm trying to find all the matches for 'test' in my string:

const search = "test";
const regexString = "(?:[^ ]+ ){0,3}" + "test" + "(?: [^ ]+){0,3}";
const re = new RegExp(regexString, "gi");
const matches = [];
const fullText = "my test string with a lot of tests that should match the test regex";
let match = re.exec(fullText);
while (match != undefined) {
    matches.push(match[1]);
    match = re.exec(fullText);
}
console.log(matches);

I'm getting the following:

[ undefined, undefined, undefined ]

Why isn't my search working?

4
  • What is the expected result? Commented Apr 16, 2018 at 22:26
  • Trying to return an array containing the 3 words preceding and proceeding 'test' Commented Apr 16, 2018 at 22:27
  • Just to clarify, if exec(..) doesn't found a match it will return null instead of undefined. Commented Apr 16, 2018 at 22:35
  • 1
    I'm not an expert of regular expressions, but if you substitute matches.push(match[1]) with matches.push(match[0]) you obtain: ["my test string with a", "lot of test", "should match the test regex"] Commented Apr 16, 2018 at 22:47

2 Answers 2

4

Your code expects the result of the match to include stuff captured in capturing groups in the regular expression. However, your regular expression contains only non-capturing groups. The (?: ) grouping explicitly does not capture the matched substring.

You want plain ( ) groupings.

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

2 Comments

Thanks. When I change to: const regexString = "([^ ]+ ){0,3}" + "test" + "( [^ ]+){0,3}"; I get: [ 'my ', 'of ', 'the ' ]. Is there a way to capture a few words before and after the 'test' search search? Sorry for beginner question regex confuses me.
@Mary right - your code expects there to be something in match[1], but if there are no real capturing groups match will always be an array with just one value. Your code currently only looks at match[1], but the regular expression (fixed) captures two groups, so you need to also look at match[2].
1

You should enclose your non-capturing groups (?:...) in a capturing group (...) since you are invoking a capturing group (match[1]). :

"((?:\\S+ ){0,3})" + search + "((?: \\S+){0,3})"

Trying to return an array containing the 3 words preceding and proceeding 'test'

Then you need to push both captured groups not one:

matches.push([match[1], search, match[2]]);
// `match[1]` refers to first capturing group
// `match[2]` refers to second CG
// `search` contains search word

JS code:

const search = "test";
const regexString = "((?:\\S+ ){0,3})" + search + "((?: \\S+){0,3})";
const re = new RegExp(regexString, "gi");
const matches = [];
const fullText = "my test string with a lot of tests that should match the test regex";
while ((match = re.exec(fullText)) != null) {
    matches.push([match[1], search, match[2]]);
}
console.log(matches);

3 Comments

This, however, doesn't output correct data on overlapping matches. A workaround would be using a lookahead construct.
Is worth mentioning that regex doesn't support repeated capturing groups so the best approach is to capture the three words (from before and after) together in a bigger capturing group.
@RodrigoFerreira It's not the regex, it's the flavor. i.e. .NET supports accessing to quantified capturing groups, each one individually.

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.