Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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*
like image 727
HereForTheAnswers Avatar asked Feb 03 '21 15:02

HereForTheAnswers


2 Answers

You can skip grep and get this done in a single awk:

xrandr | awk 'NF >= 3 && /[0-9]+x[0-9]+/ {sub(/[+-].*/, "", $3); print $3}'

1920x1200
1920x1200
primary
1029x1200

Alternative single gnu grep solution:

xrandr | grep -oP 'connected\h+\K(\d+x\d+|\S+)'
like image 112
anubhava Avatar answered Oct 08 '22 01:10

anubhava


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.
like image 20
Wiktor Stribiżew Avatar answered Oct 08 '22 00:10

Wiktor Stribiżew