Wumbo
Wumbo

Reputation: 93

Matching Word() when word is not (some word)

Specifically, I want to match functions in my Javascript code that are not in a set of common standard Javascript functions. In other words, I want to match user defined functions. I'm working with vim's flavour of regexp, but I don't mind seeing solutions for other flavours.

As I understand it, regexp crawls through a string character by character, so thinking in terms of sets of characters can be problematic even when a problem seems simple. I've tried negative lookahead, and as you might expect all the does is prevent the first character of the functions I don't want from being matched (ie, onsole.log instead of console.log).

(?(?!(if)|(console\.log)|(function))\w+)\(.*\)

function(meep, boop, doo,do)

JSON.parse(localStorage["beards"])

console.log("sldkfjls" + dododo);

if (beepboop) {

BLAH.blah.somefunc(arge, arg,arg);

https://regexr.com/

I would like to be able to crawl through a function and see where it is calling other usermade functions. Will I need to do post-processing (ie mapping with another regexp) on the matches to reject matches I don't want, or is there a way to do this in one regexp?

Upvotes: 0

Views: 41

Answers (1)

Ingo Karkat
Ingo Karkat

Reputation: 172520

The basic recipe for a regular expression that matches all words except foo (in Vim's regular expression syntax) is:

/\<\%(foo\>\)\@!\k\+\>/

Note how the negative lookahead (\@!) needs an end assertion (here: \>) on its own, to avoid that it also excludes anything that just starts with the expression!

Applied to your examples (excluding if (potentially with whitespace), console.log, and function, ending with (), that gives:

\<\%(\%(if *\|console\.log\|function\)(\)\@!\(\k\|\.\)\+\>(.*)

As you seem to want to include the entire object chain (so JSON.parse instead of just parse), the actual match includes both keyword characters (\k) and the period. There's one complication with that: The negative lookahead will latch onto the log() in console.log(), because the leading keyword boundary assertion (\<) matches there as well. We can disallow that match by also excluding a period just before the function; i.e. by placing \.\@<! in between:

\<\%(\%(if *\|console\.log\|function\)(\)\@!\.\@<!\(\k\|\.\)\+\>(.*)

That will highlight just the following calls:

JSON.parse(localStorage["beards"])
BLAH.blah.somefunc(arge, arg,arg);
foo.log(asdf)

Upvotes: 2

Related Questions