Search code examples
regexlinuxbashgrepxrandr

How to use lookahead to exclude special characters in a regular expression


I have a regular expression that I'm using to try to detect screen resolution as follows

xrandr | grep -P '(.*\d+x\d+)* | awk {'print$3'}

which when I use in my script gives me something like this

Output

1920x1200+0+0
1920x1200+1920+0
primary
1920x1200+1920+1200

I tried using lookahead, but I'm not using it correctly I guess because I'm getting the same match.

Code

xrandr | grep -P '(.*\d+x\d+)*^(?![\+]+\d\+\d) | awk {'print$3'}

Can someone explain how lookahead works with special characters so I can fix this? I want to only return the screen resolution in the form below or some variation. What I'm trying to do is distinguish between dual and 4 monitor displays.

xrandr | grep -P '(.*\d+x\d+)*^(?![\+]+\d\+\d) | awk {'print$3'} | tr -d '\\n'

Expectation

1920x12001920x1200primary1920x1200

or this

1920x1200
1920x1200
primary
1920x1200

Bonus points if it can return just the screen resolution.

1920x1200
1920x1200
1920x1200
1920x1200

xrandr output

Mon0 connected 1920x1200+0+0 0mm x 0 mm
   1920x1200_c 59.95*
Mon0 connected 1920x1200+0+0 0mm x 0 mm
   1920x1200_c 59.95*
Mon0 connected primary 1920x1200+0+1200 0mm x 0 mm
   1920x1200_c 59.95*
Mon0 connected 1029x1200+1920+1200 0mm x 0 mm
   1920x1200_c 59.95*

Solution

  • The (.*\d+x\d+)*^(?![\+]+\d\+\d) pattern matches and captures into Group 1 an optional sequence of any zero or more chars other than line break chars, as many as possible, then 1+ digits, x, 1+ digits, and then requires the start of string position (this makes the pattern fail all the time!) and makes sure there is no one or more + chars, a digit, a + and a digit immediately to the right of the current location. This looks like a very corrupt pattern that never matches any string.

    Your logic can be implemented as

    xandr | grep -oP '\b\d+x\d+(?!(?:\+\d+\+)?\d)'
    

    See the online demo and the regex demo.

    Details:

    • -oP - output matches only and enable PCRE regex engine
    • \b\d+x\d+(?!(?:\+\d+\+)?\d):
      • \b - word boundary
      • \d+ - one or more digits
      • x - an x
      • \d+ - one or more digits
      • (?!(?:\+\d+\+)?\d) - a negative lookahead that fails the match if, immediately to the right of the current location, there is
      • (?:\+\d+\+)? - an optional sequence of +, one or more digits and +
      • \d - a digit.