Canonicalize CIDR: Difference between revisions

From Rosetta Code
Content added Content deleted
(Add Factor)
Line 4: Line 4:


Example: given 87.70.141.1/22, your code should output 87.70.140.0/22.
Example: given 87.70.141.1/22, your code should output 87.70.140.0/22.

=={{header|Factor}}==
{{trans|Ruby}}
{{works with|Factor|0.99 2020-07-03}}
<lang factor>USING: command-line formatting grouping io kernel math.parser
namespaces prettyprint sequences splitting ;
IN: rosetta-code.canonicalize-cidr

! canonicalize a CIDR block: make sure none of the host bits are set
command-line get [ lines ] when-empty
[
! ( CIDR-IP -- dotted-decimal bits-in-network-part )
"/" split first2 string>number swap

! get IP as binary string
"." split [ string>number "%08b" sprintf ] map "" join

! replace the host part with all zeros
over cut length [ CHAR: 0 ] "" replicate-as append

! convert back to dotted-decimal
8 group [ bin> number>string ] map "." join swap

! and output
"%s/%d\n" printf
] each</lang>
{{out}}
<pre>
$ canonicalize-cidr.factor 87.70.141.1/22
87.70.140.0/22
</pre>


=={{header|Perl}}==
=={{header|Perl}}==

Revision as of 06:35, 9 July 2020

Task
Canonicalize CIDR
You are encouraged to solve this task according to the task description, using any language you may know.

Implement a function or program that, given a range of IPv4 addresses in CIDR notation (dotted-decimal/network-bits), will return/output the same range in canonical form. That is, the IP address portion of the output CIDR block must not contain any set (1) bits in the host part of the address.

Example: given 87.70.141.1/22, your code should output 87.70.140.0/22.

Factor

Translation of: Ruby
Works with: Factor version 0.99 2020-07-03

<lang factor>USING: command-line formatting grouping io kernel math.parser namespaces prettyprint sequences splitting ; IN: rosetta-code.canonicalize-cidr

! canonicalize a CIDR block: make sure none of the host bits are set command-line get [ lines ] when-empty [

   ! ( CIDR-IP -- dotted-decimal bits-in-network-part )
   "/" split first2 string>number swap
   ! get IP as binary string
   "." split [ string>number "%08b" sprintf ] map "" join
   ! replace the host part with all zeros
   over cut length [ CHAR: 0 ] "" replicate-as append
   ! convert back to dotted-decimal
   8 group [ bin> number>string ] map "." join swap
   ! and output
   "%s/%d\n" printf

] each</lang>

Output:
$ canonicalize-cidr.factor 87.70.141.1/22
87.70.140.0/22

Perl

<lang perl>#!/usr/bin/env perl use v5.16; use Socket qw(inet_aton inet_ntoa);

  1. canonicalize a CIDR block: make sure none of the host bits are set

if (!@ARGV) {

  chomp(@ARGV = <>);

}

for (@ARGV) {

 # dotted-decimal / bits in network part
 my ($dotted, $size) = split m#/#;
 # get IP as binary string
 my $binary = sprintf "%032b", unpack('N', inet_aton $dotted);
 # Replace the host part with all zeroes
 substr($binary, $size) = 0 x (32 - $size);
 # Convert back to dotted-decimal
 $dotted = inet_ntoa(pack 'B32', $binary);
 # And output
 say "$dotted/$size";

}</lang>

Output:
$ canonicalize_cidr.pl 87.70.141.1/22
87.70.140.0/22

Python

Translation of: Perl

<lang python>#!/usr/bin/env python

  1. canonicalize a CIDR block specification:
  2. make sure none of the host bits are set

import sys from socket import inet_aton, inet_ntoa from struct import pack, unpack

args = sys.argv[1:] if len(args) == 0:

   args = sys.stdin.readlines()

for cidr in args:

  # IP in dotted-decimal / bits in network part
  dotted, size_str = cidr.split('/')
  size = int(size_str)
  numeric = unpack('!I', inet_aton(dotted))[0]  # IP as an integer
  binary = f'{numeric:#034b}'                   # then as a padded binary string
  prefix = binary[:size + 2]                    # just the network part
                                                #   (34 and +2 are to account
                                                #    for leading '0b')
  canon_binary = prefix + '0' * (32 - size)     # replace host part with all zeroes
  canon_numeric = int(canon_binary, 2)          # convert back to integer
  canon_dotted = inet_ntoa(pack('!I',
                           (canon_numeric)))    # and then to dotted-decimal
  print(f'{canon_dotted}/{size}')               # output result</lang>
Output:
$ canonicalize_cidr.py 87.70.141.1/22
87.70.140.0/22

Raku

Translation of: Perl

<lang perl6>#!/usr/bin/env raku

  1. canonicalize a CIDR block: make sure none of the host bits are set

if (!@*ARGS) {

  @*ARGS = $*IN.lines;

}

for @*ARGS -> $cidr {

 # dotted-decimal / bits in network part
 my ($dotted, $size) = $cidr.split('/');
 # get IP as binary string
 my $binary = $dotted.split('.').map({ .fmt("%08b") }).join;
 # Replace the host part with all zeroes
 $binary.substr-rw($size) = 0 x (32 - $size);
 # Convert back to dotted-decimal
 my $canon = $binary.comb.batch(8).map({ .join.parse-base(2) }).join('.');
 # And output
 say "$canon/$size";

}</lang>

Output:
$ canonicalize_cidr.raku 87.70.141.1/22
87.70.140.0/22

Ruby

Translation of: Python
Translation of: Raku

<lang ruby>#!/usr/bin/env ruby

  1. canonicalize a CIDR block: make sure none of the host bits are set

if ARGV.length == 0 then

   ARGV = $stdin.readlines.map(&:chomp)

end

ARGV.each do |cidr|

 # dotted-decimal / bits in network part
 dotted, size_str = cidr.split('/')
 size = size_str.to_i
 # get IP as binary string
 binary = dotted.split('.').map { |o| "%08b" % o }.join
 # Replace the host part with all zeroes
 binary[size .. -1] = '0' * (32 - size)
 # Convert back to dotted-decimal
 canon = binary.chars.each_slice(8).map { |a| a.join.to_i(2) }.join('.')
 # And output
 puts "#{canon}/#{size}"

end</lang>

Output:
$ canonicalize_cidr.rb 87.70.141.1/22
87.70.140.0/22