0

I'm trying to build a RegEx that will be used against a command's output, and should match only if either of 2 strings (ex.: "down" | "error") are NOT found in a target string that has multiple lines. Here's an example of the command output I'm targeting:

Command output:
Service 1 up
Service 2 down
Service 3 up

The following RegEx, which has a negative lookahead assertion, is always matching (0 to 0), regardless of the command output:

(?!.*(down|error))

Why is it not working, and what RegEx can satisfy the request?

Thanks,

  • Silly question, but could it be because your pattern is case-sensitive? By default, all the implementations of RegEx I know of are case sensitive. So your pattern will only match `down` or `error` but wouldn't match `Down` or `Error`. Most RegEx implementations have a [`i` flag](https://stackoverflow.com/a/9655186/4416750) you can add to ignore case. – Lews Therin Jun 16 '17 at 17:28
  • I've updated the question such as to avoid any case sensitivity issues. I'm testing using The RegEx Coach (i.e. a GUI tool with the 'i' modifier checked). As such, it is not a case sensitivity issue. – TheSilverCanuck Jun 16 '17 at 18:18

2 Answers2

1

Try '^((?!(down|error)).)*$' This ensures that it matches any characters at the beginning of a string, not followed by 'down' or 'error', as many times as necessary. Note that this RegEx is case sensitive and will match a string with 'Down'.

Your RegEx would not really make any sense because it includes a negative lookahead but nothing to look ahead from. Thus, it would match 0 characters (or the empty string ''), not followed by any number of characters and then 'down' or 'error'. Even if you had the characters 'down' or 'error' in your string, you would still match within the pattern 'down' or 'error' for your RegEx.

NOTE: Negative assertions are intended for smaller rules, not for whole strings. The most commonly used example is to find a q without a u after it, such as in sheqalim. In this case, you might want to find the position of the q. However, with your case, it seems like you just want to determine whether 'down' or 'error' are contained in your string, with which it is more efficient and simpler to use a built in function, if whatever language you are using has one. If it doesn't, it would also be easier to see if you can match 'down' or 'error' and negate that. The RegEx I provided should be a last resort.

victor
  • 1,573
  • 11
  • 23
  • I've tried your suggestion, and now the RegEx never matches, even in the following case, where all of my services are 'Up': Command output: Service 1 Up Service 2 Good Service 3 OK Service 4 Up – TheSilverCanuck Jun 16 '17 at 18:29
  • @TheSilverCanuck I made a typo with the RegEx. I edited the answer. – victor Jun 16 '17 at 18:50
  • RegExr says you still have an infinite match problem. Maybe you meant + instead of * – NH. Jun 19 '17 at 18:58
  • @NH. That's not what I'm getting...it works for me on RegExr. Are you typing any text into the sample text textarea? – victor Jun 19 '17 at 19:01
  • Either way, infinite match (on zero characters) is a problem independent of which body of text you feed it. Note that * matches Zero or More occurrences. – NH. Jun 19 '17 at 19:50
  • @NH. Yes, but negative lookaheads are different. The RegEx is basically trying to match a string where the beginning of the string is not followed by one or more occurences of 'down' or 'error'. If there are no occurences where the beginning is followed by 'down' or 'error', the `*` will match the string because that is what is desired. Seriously, have you even tested the RegEx or are you just blowing steam? – victor Jun 19 '17 at 20:16
1

First of all, testing for absence of a pattern is generally not the right way to do things in regular expressions and you would be much better off using the regular expression:

/(down|error)/mi

and then negating the boolean indicating whether the expression matched.

However, only if there is no way to negate the match, you can use something like /^Command output:\s\s?(.*up\s\s?)+(.*up)?$/i to ensure every line ends in the word "up".

NH.
  • 2,240
  • 2
  • 23
  • 37
  • I understand your comment about testing for the absence of a pattern (and your recommended solution) , but I thought that that was what negative assertions were for? Furthermore, the tool using the RegEx (i.e. System Center Operations Manager) only offers me the ability to provide a RegEx test to determine if the command output is "healthy". Also, the only way I know that the output is "Healthy" is if there are no "down" or "error" strings in the output, which could contain any number of services\lines (i.e. "Service 1, Service 2,...Service n). – TheSilverCanuck Jun 16 '17 at 18:27
  • OK, it would have been good to briefly mention that constraint in the original question. My answer doesn't really apply to your exact situation (but might work for others who don't have that constraint). – NH. Jun 19 '17 at 18:33