6

I have a specific pattern that I want to search for in Visual Studio.

Basically, I want to search for lines that contains await, but are missing ConfigureAwait at the end of the statement.

I have some patterns that works in regex-testers such as regex101.com, but I can't get these patterns to work in Visual Studio search. For example, the pattern (?s)^(.)*(await)((?!ConfigureAwait).)*(.)?(;).

What I am doing wrong?

Edit - I want to find lines in my project such as

await DoSomeCoolThings(x, y); (i.e. missing the ConfigureAwait(...).)

but I don't want to get a match for lines such as:

await DoSomeCoolThings(x, y).ConfigureAwait(false);

BuilderBee
  • 132
  • 1
  • 7
Superhubert
  • 141
  • 1
  • 11
  • Remove the `/.../`... What does the input look like? Please post some sample string or share a link to the online tester fiddle at least. Also, remove `(?s)` and replace `.` with `[\s\S\r]`. Note that `(.)*` is a bad approach to quantifying groups - as one symbol is captured infinite number of times, it creates redundant overhead for the regex engine. Use `(.*)` (if you need to capture at all). I think most of the capture groups are redundant here (until you clarify what you are doing). – Wiktor Stribiżew Apr 19 '16 at 06:58
  • 1
    `(?=.*await)(?!.*ConfigureAwait)` should also work – rock321987 Apr 19 '16 at 07:08
  • Sorry, the slashes are not part of the pattern. I've removed them from my example pattern. – Superhubert Apr 19 '16 at 07:08
  • @rock321987 - this works. Thank you! – Superhubert Apr 19 '16 at 07:13
  • glad, it worked for you – rock321987 Apr 19 '16 at 07:15

3 Answers3

5

If the order of await and ConfigureAwait does not matter, then you can use

(?=.*\bawait\b)(?!.*\bConfigureAwait\b)

otherwise, if you consider that ConfigureAwait should come after await, you can use

(?=.*\bawait\b(?!.*\bConfigureAwait\b))

Efficient Solution

(?=\bawait\b(?!.*\bConfigureAwait\b))
rock321987
  • 10,942
  • 1
  • 30
  • 43
  • I wonder how `ConfigureAwait` can come before `await` :) That first unanchored lookahead is unnecessary complication here. – Wiktor Stribiżew Apr 19 '16 at 07:29
  • @WiktorStribiżew I was thinking it from regex point of view..:) – rock321987 Apr 19 '16 at 07:31
  • If the document is large, your regex will slow down matching because the unanchored lookarounds are checked *at each and every location in the text*. You see, in my expression, the whole line is grabbed first, then, backtracking finds the `await`, and then the negative lookahead triggers. In your case, the engine checks the beginning of the string: grabs all, backtracks, finds or not, triggered the negative lookahead, and goes on like this at each location, before each character. It is highly inefficient, and is bad practice when *global matching* is involved (like here, `/g` is implied). – Wiktor Stribiżew Apr 19 '16 at 07:43
  • @WiktorStribiżew wait..but the debugger mode does not says so..can you please clarify a bit more – rock321987 Apr 19 '16 at 07:53
  • (I guess I removed my comment): Sorry, I meant highlighting. – Wiktor Stribiżew Apr 19 '16 at 07:57
  • @WiktorStribiżew you can compare my second regex with yours.. First one is inefficient :- I agree, but its for checking if one word is present and other is not anywhere in the string – rock321987 Apr 19 '16 at 08:04
  • The second one is of the same structure (unanchored lookaround). You know regex101 - you can quickly see the difference there. – Wiktor Stribiżew Apr 19 '16 at 08:06
  • @WiktorStribiżew i am using that site only for the comparison..There is only a difference of two steps between my second regex and yours even in the case of no match – rock321987 Apr 19 '16 at 08:07
  • See the regex debugger with PCRE. And all depends on the input string as usual. BTW, `.*?\bawait\b(?!.*\bConfigureAwait\b).*` - 45 steps, and [`(?=.*\bawait\b(?!.*\bConfigureAwait\b))`](https://regex101.com/r/qT4qN6/1) - 83. – Wiktor Stribiżew Apr 19 '16 at 08:09
  • @WiktorStribiżew I was comparing `.*\bawait\b(?!.*\bConfigureAwait\b).*` regex which you have written initially, and it takes `82` steps..If I modify my regex to `(?=\bawait\b(?!.*\bConfigureAwait\b))`, it takes `45` steps – rock321987 Apr 19 '16 at 08:53
  • Cool. I just though that a *line* must be matched that is why I used consuming `.*`. Those may really be unnecessary. – Wiktor Stribiżew Apr 19 '16 at 09:00
  • @WiktorStribiżew that's what I was thinking..also I can use lazy quantifier(as you have used) in my regex and it will work again with difference of two steps – rock321987 Apr 19 '16 at 09:01
2

I do not think we should be constrained to a single line, as more complicated statements can be split up into multiple lines. Also, the solution should preferably be fast.

To that effect, we can either use the Resharper plugin "ConfigureAwait Checker", or the following regex:

\bawait\b(?![^;]*ConfigureAwait)[^;]*;

The idea is to find the word "await", and then read the entire statement until its semicolon ;, matching only if the word "ConfigureAwait" is missing in that text. More specifically:

  1. \bawait\b: Whole word "await".
  2. (?!...): Negative lookahead that we will use to exclude matches that already have ConfigureAwait.
    • [^;]*ConfigureAwait: The word "ConfigureAwait", preceded by any number of characters that are not the semicolon.
  3. [^;]*: Any number of characters that are not the semicolon.
  4. The semicolon.

I got a few minor false positives where the statement contains a query string (with a semicolon) or a lambda (with a semicolon). They were so easily ignored that I did not find it worthwhile to further complicate the regex.

Timo
  • 7,992
  • 4
  • 49
  • 67
1

To match these lines with await but without ConfigureAwait after it, you can use a simpler negative lookahead based regex:

.*\bawait\b(?!.*\bConfigureAwait\b).*

The pattern matches any non-newline symbols (.*) followed with a whole word await (as \b are word boundaries) and then a check is performed to make sure there is no whole word ConfigureAwait somewhere after await (with a lookahead (?!.*\bConfigureAwait\b)), and then the rest of line is matched with .*.

enter image description here

Since await is usually close to the left side of the string, best is to use a lazy dot matching at the beginning:

.*?\bawait\b(?!.*\bConfigureAwait\b).*
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563