Regex for DHCP leases file is not working as expected

I am using a regex pattern to match the dhcp leases data file.

(?mis)^lease\s+(\S+)(?:(?!^lease\s).)*?binding state\s+(active|inactive|offline|free|abandoned?).*?(\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2});.*?vendor-class\s*(\"[^\"]+\");.*?[^}]

But the above regex is not matching properly. For example if I have a example dhcp.leases file in below format.

 lease {
  starts 1 2022/04/25 17:31:27;
  ends 1 2022/04/25 17:33:27;
  cltt 1 2022/04/25 17:31:27;
  binding state free;
  hardware ethernet LL:KK:JJ:HH:DD:SS;
  uid "SDS";
    vendor-class "test1";
  set vendor-class-identifier = "test1";
  client-hostname "MNOP";
lease {
  starts 3 2022/04/27 14:41:30;
  ends 3 2022/05/04 14:41:30;
  cltt 3 2022/04/27 14:41:30;
  binding state active;
  next binding state free;
  rewind binding state free;
  hardware ethernet MM:NN:DD:SS:RR:WW;
  uid "SASa";
  client-hostname "ADBC";
lease {
  starts 3 2022/04/20 18:22:44;
  ends 5 2022/05/20 18:22:44;
  cltt 3 2022/04/20 18:22:44;
  binding state active;
  next binding state free;
  rewind binding state free;
  hardware ethernet AA:BB:CC:DD:FF:FF;
  uid "dasdad";
    vendor-class "test 3 vendor";
  set vendor-class-identifier = "test3";

Here In the second lease I am not having vendor-class filed which I am using in regex, so instead of skipping the vendor-class filed its trying to match the same in third lease, because of that I am getting only 2 match groups instead of 3 match groups. its merging 2nd and 3rd lease as one lease. Please help me out.
Please find the below link for better understanding:

>Solution :

You can use

(?mis)^lease\s+(\S+)(?:(?!^lease\s).)*?binding state\s+(active|inactive|offline|free|abandoned?)(?:(?!^lease\s).)*?(\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2})(?:(?:(?!^lease\s).)*?vendor-class\s*(\"[^\"]+\").*?\s*(\"[^\"]+\");)?[^}]*

See the regex demo


  • Replace all .*? but last with the tempered greedy token, (?:(?!^lease\s).)*?, to avoid the section overflow during a match
  • Make sure the vendor matching pattern part is optional, see the (?:(?:(?!^lease\s).)*?vendor-class\s*(\"[^\"]+\").*?\s*(\"[^\"]+\");)? pattern, where the (?:(?!^lease\s).)*?vendor-class\s*(\"[^\"]+\").*?\s*(\"[^\"]+\"); is wrapped with the optional non-capturing group (see How do I make part of a regex match optional?)

Leave a Reply