Question

Stack Overflow RegEx Wizards, I've scoured Google and haven't quite found a good solution for this. I need to pull out 1:N DNS servers from IPCONFIG results. In the example below, I would need the first three. However, there may be an instance where there are more or less.

Update: Optimally we want to place cursor at first colon(:) in the DNS string then capture IPs until we hit an alpha character. So if we can just scrape a string from that colon to that alpha character we can run another RegEx to match IPs.

DNS.*: gets us to the first colon (:)

Need to read-ahead until alpha character.

Important Note: Because of the third-party tool we're using we can only use RegEx :)

Here's the RegEx value I've been using as for IPs. This will capture all IP's instead of just the DNS ones...

(([0-9]){1,3}.){1,3}[0-9]{1,3}

IPCONFIG Example

    Subnet Mask . . . . . . . . . . . : 255.255.255.0
    Default Gateway . . . . . . . . . : 152.225.244.1
    DHCP Server . . . . . . . . . . . : 10.204.40.57
    DNS Servers . . . . . . . . . . . : 10.204.127.11
                                        10.207.2.50
                                        10.200.10.6
    Primary WINS Server . . . . . . . : 10.207.40.145
    Secondary WINS Server . . . . . . : 10.232.40.38
    Lease Obtained. . . . . . . . . . : Tuesday, August 28, 2012 6:45:12 AM
    Lease Expires . . . . . . . . . . : Sunday, September 02, 2012 6:45:12 A
Was it helpful?

Solution

#!/usr/bin/env perl

use strict;
use warnings;

my $data = <<END;
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 152.225.244.1
DHCP Server . . . . . . . . . . . : 10.204.40.57
DNS Servers . . . . . . . . . . . : 10.204.127.11
                                    10.207.2.50
                                    10.200.10.6
Primary WINS Server . . . . . . . : 10.207.40.145
Secondary WINS Server . . . . . . : 10.232.40.38
Lease Obtained. . . . . . . . . . : Tuesday, August 28, 2012 6:45:12 AM
Lease Expires . . . . . . . . . . : Sunday, September 02, 2012 6:45:12 A
END

my @ips = ();

if ($data =~ /^DNS Servers[\s\.:]+((\d{2}\.\d{3}\.\d{1,3}\.\d{1,3}\s*)+)/m) {
    @ips = split(/\s+/, $1);
    print "$_\n" foreach(@ips);
}

OTHER TIPS

I would use unpack instead of regular expressions for parsing column-based data:

#!/usr/bin/env perl

use strict;
use warnings;

while (<DATA>) {
    my ($ip) = unpack 'x36 A*';
    print "$ip\n";
}

__DATA__
DNS Servers . . . . . . . . . . . : 10.204.127.11
                                    10.207.2.50
                                    10.200.10.6
Primary WINS Server . . . . . . . : 10.207.40.145
Secondary WINS Server . . . . . . : 10.232.40.38

You may have to adjust the number 36 to the actual number of characters that should be skipped.

Personally, I'd go in a different direction. Instead of manually parsing the output of ipconfig, I'd use the Win32::IPConfig module. Win32::IPConfig - IP Configuration Settings for Windows NT/2000/XP/2003

use Win32::IPConfig;
use Data::Dumper;

my $host = shift || "127.0.0.1";
my $ipconfig = Win32::IPConfig->new($host);

my @searchlist = $ipconfig->get_searchlist;
print Dumper \@searchlist;

Match

DNS.+?:(\s*([\d.]+).)+

and pull out the groups. This assumes you have the entire multi-line string in one blob, ans that the extracted text may contain newlines and other whitespace. The last dot is to match the newline, you need to use /m option

Match against this regex (see in action):

DNS Servers.*:\s*(.*(?:[\n\r]+\s+.*(?:[\n\r]+\s+.*)?)?)

First capture group will be your three IP's (atmost three) as you requested. You need to trim whitespaces surely.

Edit: Regex fixed to match at most three IP's. If there is less IP's, matches them only.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top