views:

171

answers:

2

I'm working on this pretty big re-factoring project and I'm using intellij's find/replace with regexp to help me out.

This is the regexp I'm using:

\b(?<!\.)Units(?![_\w(.])\b

I find that most matches that are not useful for my purpose are the matches that occur with strings within quotes, for example: "units"

I'd like to find a way to have the above expression not match when it finds a matching string that's between quotes...

Thx in advance, this place rocks!

+1  A: 

Assuming the quotes are always paired on a given line, you could create matches before and after for an even number of quotes, and make sure the whole line is matched:

^([^"]*("[^"]*")*[^"]*)*\b(?<!\.)Units(?![_\w(.])\b([^"]*("[^"]*")*[^"]*)*$

this works because the fragment

([^"]*("[^"]*")*[^"]*)*

will only match paired quotes. By adding the begin and end line anchors, it forces the quotes on the left and right side of your regex to be an even count.

This won't handle embedded escaped quotes properly, and multiline quoted strings will be trouble.

Michael Donohue
OK, some things are missing from this expression: first of all it only matches one character between quotes. You should change the middle `[^"]` to `[^"]*`. And it only matches one pair of quotes before and after `Units`, so the whole paired expression should be wrapped in a group and a Kleene closure: `([^"]*("[^"]*")[^"]*)*`. But even then it doesn't match pathological cases like the one I put in my comment on the question: `"\"" + Number + " (" + Units ")\""`. My point is regular expressions aren't the answer. Just look how complicated this expression is. Software is supposed to be simple.
Welbog
Updated to reflect the corrections suggested. The pathological cases were already enumerated in my answer, I'm not trying to hide or ignore them, but sometimes the workload doesn't have pathological cases. Building a tokenizer is significantly more work than adding a couple dozen characters to a regex. Software is supposed to be simple.
Michael Donohue
Good comeback. I don't have full knowledge of every IDE out there, but I'm reasonably sure they already come with parsers (for syntax highlighting) that have already tokenized the code and can easily search for named tokens rather than treating the code as a string. While the code to tokenize code is certainly more complicated than most stand-alone regular expressions, it's conceptually simpler to scan tokenized code than it is to scan code as a set of strings. When I say "software is supposed to be simple", I am referring to the ability to easily understand what is going on at a high level.
Welbog
Also +1 for this expression. I've tested it and it works as you say it should. This particular answer is fine, and the approach is correct. It's just that regular expressions aren't suited for the general case.
Welbog
+1  A: 

Intellij uses Java regexes, doesn't it? Try this:

(?m)(?<![\w.])Units(?![\w(.])(?=(?:[^\r\n"\\]++|\\.)*+[^\r\n"\\]*+$)

The first part is your regex after a little cosmetic surgery:

(?<![\w.])Units(?![\w(.])

The \b at the beginning and end were effectively the same as a negative lookbehind and a negative lookahead (respectively) for \w, so I folded them into your existing lookarounds. The new lookahead matches the rest of the line if it contains even number (including zero) of unescaped quotation marks:

(?=(?:[^\r\n"\\]++|\\.)*+[^\r\n"\\]*+$)

That handles pathological cases like the one Welbog pointed out, and unlike Michael's regex it will find multiple occurrences of the text the same line. But it doesn't take comments into account. Is Intellij's find/replace feature intelligent enough to disregard text in comments? Come to think of it, doesn't it have some kind of refactoring support built in?

Alan Moore
+1 because I admire your perseverance in solving the wrong problem with the wrong solution and ending up with an answer that works.
Welbog
:) Some people wrestle alligators, I wrestle regexes.
Alan Moore