0

I have a text file that contains IP address ranges defined as follows:

10.30.8.4
10.30.6.[10:12]
10.30.[8:9].4
[10:11].30.12.23
[10:11].[28:29].[11:12].[22:23]

by parsing this with a regex, I'm expecting the output to be

10.30.8.4
10.30.6.10
10.30.6.11
10.30.6.12
10.30.8.4
10.30.9.4
10.30.12.23
11.30.12.23
10.28.11.22
10.28.11.23
10.28.12.22
10.28.12.23
10.29.11.22
10.29.11.23
10.29.12.22
10.29.12.23
11.28.11.22
11.28.11.23
11.28.12.22
11.28.12.23
11.29.11.22
11.29.11.23
11.29.12.22
11.29.12.23

this is what I got so far

$ips = Get-Content C:\temp\hosts.txt
$regex = [regex] "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"

$regex.Matches($ips) | %{ $_.value }

This only gets the first IP address but not the others

2
  • 1
    Maybe I'm misunderstanding, but this isn't how regex works. You could match the collapsed input ranges you have, but regex is not going to expand them into IP addresses. Commented Jul 13, 2016 at 17:54
  • yes. You are right. Regex wont solve the problem. Need to use some kind of loop to do the expansion Commented Jul 13, 2016 at 20:11

3 Answers 3

2

Sad to say this, but regex is totally the wrong tool for the job, although you can use regexes as part of a nutritionally balanced solution:

foreach ($line in (Get-Content D:\data.txt))
{
    if ($line -match ':') 
    {
            $Left, $Range, $Right = $line -split '\[(.*)\]'
            $start, $end = $Range -split ':'
            $start..$end |% { "$Left$_$Right" }
    } 
    else 
    {
        $line
    }
}

NB. "IP address ranges defined as follows" doesn't define anything, it's just three examples. I've completely guessed what it's supposed to mean. Ymmv.


Edit for your edit: completely different if each chunk could be a range or not. I've broken out a function to make each item iterable, either a direct number stays as a number, or a range expands to all the items in the range. Four nested loops isn't so bad, but I wouldn't want to do this for IPv6...

Function Get-ExpandedBlock {
    Param($block)
    # Takes an IP chunk, either a number '10' or a range '[10:12]'
    # Returns either the number: '10' or
    # a PowerShell range over the input range: 10,11,12

    if ($block -match ':') {
        $start, $end = $block.Trim('[]') -split ':'
        $start..$end
    } else {
        $block
    }
}

$fullList = foreach ($line in (Get-Content D:\data.txt)) {
    $a, $b, $c, $d = $line.Split('.')

    foreach ($w in Get-ExpandedBlock $a) {
     foreach ($x in Get-ExpandedBlock $b) {
      foreach ($y in Get-ExpandedBlock $c) {
       foreach ($z in Get-ExpandedBlock $d) {
           "$w.$x.$y.$z"
       }
      }
     }
    }
}

$fullList
Sign up to request clarification or add additional context in comments.

3 Comments

Tthis looks correct. Thanks. One small issue is that it doesn't seem to work when there are multiple expansions in the same line. ex: [10:11].[12:13].[20:23].[100:102]
"The question you answered? That wasn't my *real question! /evil laughter*"; Yeah, my code won't handle stuff you didn't mention - why would it?
Cool. Works as I expected. Thanks again
0
   List<String> resolveRange( String iprange )
   {
      List<String> ipList = new ArrayList<String>();
      if ( iprange.indexOf( "[" ) < 0 )
      {
         ipList.add( iprange );
      }
      else
      {
         String[] sections = iprange.split( "\\." );
         Object[] output = new Object[4];
         int count = 1;
         int index = 0;
         for ( String section : sections )
         {
            List<String> ips = resolve( section );
            count *= ips.size();
            output[index++] = ips;
         }

         ipList = new ArrayList<String>( count );
         List<String> section1 = (List<String>) output[0];
         List<String> section2 = (List<String>) output[1];
         List<String> section3 = (List<String>) output[2];
         List<String> section4 = (List<String>) output[3];

         for ( String first : section1 )
         {
            for ( String second : section2 )
            {
               for ( String third : section3 )
               {
                  for ( String four : section4 )
                  {
                     ipList.add( new StringBuilder().append( first ).append( "." ).append( second ).append( "." ).append( third ).append( "." ).append( four ).toString() );
                  }
               }
            }
         }
      }

      return ipList;
   }

   List<String> resolve( String section )
   {
      List<String> listString = new ArrayList<String>();

      if ( section.indexOf( "[" ) >= 0 )
         listString = parse( section );
      else
         listString.add( section );
      return listString;
   }

   List<String> parse( String rangeString )
   {
      String[] arr = rangeString.replaceAll( "[\\[\\]]", "" ).split( ":" );
      int start = Integer.valueOf( arr[0] );
      int end = Integer.valueOf( arr[1] );

      List<String> nums = new ArrayList<String>();
      while ( start <= end )
      {
         nums.add( String.valueOf( start++ ) );
      }

      return nums;
   }

Comments

-1

You cannot, in general, use regular expressions for this sort of problem, where part of the pattern may vary, or perhaps that part, with some condition enforced over the whole string, as in, EITHER that octet is replaced by a range, OR THAT octet is replaced by a range. It doan't phytte.

The proper medium for solving this problem is AWK. You can recognize any of the five pattern archetypes:

range "." digits "." digits "." digits
digits "." range "." digits "." digits
digits "." digits "." range "." digits
digits "." digits "." digits "." range
digits "." digits "." digits "." digits

and, in any but the fifth, loop over the values implicitly specified by the "range" to generate all the addresses in the family, using the pseudo-variables $1, $3, $5, and/or $7 as appropriate to refer to the various address parts.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.