Canonicalize CIDR: Difference between revisions

Add Swift implementation
(Added Algol 68)
(Add Swift implementation)
 
(41 intermediate revisions by 20 users not shown)
Line 12:
 
;Explanation:
An Internet Protocol version 4 address is a 32-bit value, conventionally represented as a number in base 256 using dotted-decimal notation, where each base-256 "digit" is represented by the digit valuegiven in decimal and the digits are separated by periods. Logically, this 32-bit value represents two components: the leftmost (most-significant) bits determine the "network" portion of the address, while the rightmost (least-significant) bits determine the "host" portion. Classless Internet Domain Routing block notation indicates where the boundary between these two components is for a given address by adding a slash followed by the number of bits in the network portion.
 
In general, CIDR blocks stand in for the entire set of IP addresses sharing the same "network" component;, so it's common to see access control lists that specify a singleindividual IP addressaddresses using CIDR with /32 to indicate that only the one address is included. Often,Software the tools usingaccepting this notation expectas theinput addressoften expects it to be entered in canonical form, in which the "host" bits are all zeroes. inBut thenetwork binaryadmins representation.sometimes Butskip carelessthis networkstep adminsand mayjust provideenter CIDRthe blocksaddress withoutof canonicalizinga themspecific first.host Thison taskthe handlessubnet with the canonicalizationnetwork size, resulting in a non-canonical entry.
 
The example address, 87.70.141.1/22, translates into 01010111010001101000110100000001 inrepresents binary notation zero-padded to 32 bits. The0101011101000110100011 /22 means0100000001, thatwith the first/ 22 of those bits determineindicating the match;network/host the final 10 bits should be 0division. ButTo theycanonicalize, insteadclear includeall two 1the bits: 0100000001.to Sothe toright canonicalizeof the address,/ changeand thoseconvert 1'sback to 0'sdotted todecimal: yield0101011101000110100011 01010111010001101000110000000000,/ which in dotted-decimal0000000000 is 87.70.140.0.
 
 
Line 31:
{{trans|C}}
 
<langsyntaxhighlight lang="11l">F cidr_parse(str)
V (addr_str, m_str) = str.split(‘/’)
V (a, b, c, d) = addr_str.split(‘.’).map(Int)
Line 41:
| d < 0 | d > 255
R (0, 0)
V mask = (-)~((1 << (32 - m)) - 1)
V address = (a << 24) + (b << 16) + (c << 8) + d
address [&]= mask
Line 63:
‘184.232.176.184/18’]
V (address, mask_length) = cidr_parse(test)
print(‘#<18 -> #.’.format(test, cidr_format(address, mask_length)))</langsyntaxhighlight>
 
{{out}}
Line 76:
 
=={{header|ALGOL 68}}==
<langsyntaxhighlight lang="algol68">BEGIN # show IPv4 addresses in CIDR notation in canonical form #
# mode to hold an IPv4 address in CIDR notation #
MODE CIDR = STRUCT( BITS address
Line 92:
INT dot count := 0;
INT slash count := 0;
INT digit count := 0;
BOOL valid := TRUE;
INT s pos := LWB addr;
Line 129 ⟶ 128:
# invalid character #
valid := FALSE;
error := "UnvalidInvalid character: """ + addr[ s pos ] + """"
FI
OD;
Line 197 ⟶ 196:
FI
OD
END</langsyntaxhighlight>
{{out}}
<pre>
Line 207 ⟶ 206:
184.232.176.184/18 -> 184.232.128.0/18
</pre>
=={{header|APL}}==
{{works with|Dyalog APL}}
<syntaxhighlight lang="apl"> canonicalize←{
nums←(2⊃⎕VFI)¨(~⍵∊'./')⊆⍵
ip len←(4↑nums)(5⊃nums)
ip←(32/2)⊤256⊥⊃¨ip
ip←ip∧32↑len⍴1
ip←(4/256)⊤2⊥ip
(1↓∊'.',¨⍕¨ip),'/',⍕len
}</syntaxhighlight>
{{out}}
<syntaxhighlight lang="apl"> canonicalize '87.70.141.1/22'
87.70.140.0/22</syntaxhighlight>
 
=={{header|BASIC}}==
==={{header|Commodore BASIC}}===
<syntaxhighlight lang="gwbasic">100 REM THE BINARY OPS ONLY WORK ON SIGNED 16-BIT NUMBERS
110 REM SO WE STORE THE IP ADDRESS AS AN ARRAY OF FOUR OCTETS
120 DIM IP(3)
130 REM READ DEMO DATA
140 READ CI$
150 IF CI$="" THEN END
160 REM FIND /
170 SL=0
180 FOR I=LEN(CI$) TO 1 STEP -1
190 : IF MID$(CI$,I,1)="/" THEN SL=I:I=1
200 NEXT I
210 IF SL=0 THEN PRINT "INVALID CIDR STRING: '"CI$"'":GOTO 140
220 NW=VAL(MID$(CI$,SL+1))
230 IF NW < 1 OR NW > 32 THEN PRINT "INVALID NETWORK WIDTH:"NW:GOTO 140
240 REM PARSE OCTETS INTO IP ARRAY
250 BY=0:N=0
260 FOR I=1 TO SL-1
270 : C$=MID$(CI$,I,1):IF C$<>"." THEN 300
280 : IP(N)=BY:N=N+1:BY=0:IF IP(N-1)<256 THEN 310
290 : PRINT "INVALID OCTET VALUE:"IP(N-1):GOTO 140
300 : C=VAL(C$):IF C OR (C$="0") THEN BY=BY*10+C
310 NEXT I
320 IP(N)=BY:N=N+1:IF IP(N-1)>255 THEN 290
330 REM NUMBER OF COMPLETE OCTETS IN NETWORK PART
340 NB=INT(NW/8)
350 REM NUMBER OF NETWORK BITS IN PARTIAL OCTET
360 XB=NW AND 7
370 REM ZERO OUT HOST BITS IN PARTIAL OCTET
380 IP(NB) = IP(NB) AND (255 - 2^(8-XB) + 1)
390 REM AND SET ANY ALL-HOST OCTETS TO 0
400 IF NB<3 THEN FOR I=NB+1 TO 3:IP(I)=0 :NEXT I
410 REM PRINT OUT THE RESULT
420 PRINT MID$(STR$(IP(0)),2);
430 FOR I=1 TO 3: PRINT "."MID$(STR$(IP( I)),2);:NEXT I
440 PRINT MID$(CI$,SL)
450 REM AND GO BACK FOR NEXT INPUT
460 GOTO 140
500 DATA 87.70.141.1/22, 36.18.154.103/12, 62.62.197.11/29
510 DATA 67.137.119.181/4, 161.214.74.21/24, 184.232.176.184/18
520 REM SOME INVALID INPUTS
530 DATA 127.0.0.1, 123.45.67.89/0, 98.76.54.32/100, 123.456.789.0/12
540 DATA</syntaxhighlight>
 
{{Out}}<pre>READY.
RUN
87.70.140.0/22
36.16.0.0/12
62.62.197.8/29
64.0.0.0/4
161.214.74.0/24
184.232.128.0/18
INVALID CIDR STRING: '127.0.0.1'
INVALID NETWORK WIDTH: 0
INVALID NETWORK WIDTH: 100
INVALID OCTET VALUE: 456
 
READY.</pre>
 
==={{header|FreeBASIC}}===
{{trans|Commodore BASIC}}
<syntaxhighlight lang="vb">#lang "qb"
 
REM THE Binary OPS ONLY WORK On SIGNED 16-Bit NUMBERS
REM SO WE STORE THE IP ADDRESS As AN ARRAY OF FOUR OCTETS
Cls
Dim IP(3)
Do
REM Read DEMO Data
140 Read CI$
If CI$ = "" Then Exit Do 'Sleep: End
REM FIND /
SL = 0
For I = Len(CI$) To 1 Step -1
If Mid$(CI$,I,1) = "/" Then SL = I : I = 1
Next I
If SL = 0 Then Print "INVALID CIDR STRING: '"; CI$; "'": Goto 140
NW = Val(Mid$(CI$,SL+1))
If NW < 1 Or NW > 32 Then Print "INVALID NETWORK WIDTH:"; NW: Goto 140
REM PARSE OCTETS INTO IP ARRAY
BY = 0 : N = 0
For I = 1 To SL-1
C$ = Mid$(CI$,I,1)
If Not (C$ <> ".") Then
IP(N) = BY : N = N + 1
BY = 0
If IP(N-1) < 256 Then 310
Print "INVALID OCTET VALUE:"; IP(N-1): Goto 140
Else C = Val(C$):If C Or (C$="0") Then BY = BY*10+C
End If
310 '
Next I
IP(N) = BY : N = N + 1
If IP(N-1) > 255 Then Print "INVALID OCTET VALUE:"; IP(N-1): Goto 140
REM NUMBER OF COMPLETE OCTETS IN NETWORK PART
NB = Int(NW/8)
REM NUMBER OF NETWORK BITS IN PARTIAL OCTET
XB = NW And 7
REM ZERO Out HOST BITS IN PARTIAL OCTET
IP(NB) = IP(NB) And (255 - 2^(8-XB) + 1)
REM And SET Any ALL-HOST OCTETS To 0
If NB < 3 Then For I = NB +1 To 3 : IP(I) = 0 : Next I
REM Print Out THE RESULT
Print Mid$(Str$(IP(0)),2);
For I = 1 To 3
Print "."; Mid$(Str$(IP( I)),2);
Next I
Print Mid$(CI$,SL)
Loop
Data "87.70.141.1/22", "36.18.154.103/12", "62.62.197.11/29"
Data "67.137.119.181/4", "161.214.74.21/24", "184.232.176.184/18"
REM SOME INVALID INPUTS
Data "127.0.0.1", "123.45.67.89/0", "98.76.54.32/100", "123.456.789.0/12"
 
Sleep</syntaxhighlight>
{{out}}
<pre>Similar to Commodore BASIC entry.</pre>
 
==={{header|QBasic}}===
{{trans|Commodore BASIC}}
{{works with|QBasic|1.1}}
{{works with|QuickBasic|4.5}}
<syntaxhighlight lang="qbasic">CLS
DIM IP(3)
DO
REM Read DEMO Data
140 READ CI$
IF CI$ = "" THEN EXIT DO 'Sleep: End
REM FIND /
SL = 0
FOR I = LEN(CI$) TO 1 STEP -1
IF MID$(CI$, I, 1) = "/" THEN SL = I: I = 1
NEXT I
IF SL = 0 THEN PRINT "INVALID CIDR STRING: '"; CI$; "'": GOTO 140
NW = VAL(MID$(CI$, SL + 1))
IF NW < 1 OR NW > 32 THEN PRINT "INVALID NETWORK WIDTH:"; NW: GOTO 140
REM PARSE OCTETS INTO IP ARRAY
BY = 0: N = 0
FOR I = 1 TO SL - 1
C$ = MID$(CI$, I, 1): IF C$ <> "." THEN 300
IP(N) = BY: N = N + 1: BY = 0: IF IP(N - 1) < 256 THEN 310
290 PRINT "INVALID OCTET VALUE:"; IP(N - 1): GOTO 140
300 C = VAL(C$): IF C OR (C$ = "0") THEN BY = BY * 10 + C
310 '
NEXT I
IP(N) = BY: N = N + 1: IF IP(N - 1) > 255 THEN 290
REM NUMBER OF COMPLETE OCTETS IN NETWORK PART
NB = INT(NW / 8)
REM NUMBER OF NETWORK BITS IN PARTIAL OCTET
XB = NW AND 7
REM ZERO Out HOST BITS IN PARTIAL OCTET
IP(NB) = IP(NB) AND (255 - 2 ^ (8 - XB) + 1)
REM And SET Any ALL-HOST OCTETS To 0
IF NB < 3 THEN FOR I = NB + 1 TO 3: IP(I) = 0: NEXT I
REM Print Out THE RESULT
PRINT MID$(STR$(IP(0)), 2);
FOR I = 1 TO 3
PRINT "."; MID$(STR$(IP(I)), 2);
NEXT I
PRINT MID$(CI$, SL)
LOOP
DATA 87.70.141.1/22, 36.18.154.103/12, 62.62.197.11/29
DATA 67.137.119.181/4, 161.214.74.21/24, 184.232.176.184/18
REM SOME INVALID INPUTS
DATA 127.0.0.1, 123.45.67.89/0, 98.76.54.32/100, 123.456.789.0/12
DATA</syntaxhighlight>
{{out}}
<pre>Similar to Commodore BASIC entry.</pre>
 
==={{header|uBasic/4tH}}===
<syntaxhighlight lang="uBasic/4tH">If Try (_CanonicalizeCIDR ("36.18.154.103/12")) Then Print "Illegal IP"
If Try (_CanonicalizeCIDR ("62.62.197.11/29")) Then Print "Illegal IP"
If Try (_CanonicalizeCIDR ("67.137.119.181/4")) Then Print "Illegal IP"
If Try (_CanonicalizeCIDR ("161.214.74.0/24")) Then Print "Illegal IP"
If Try (_CanonicalizeCIDR ("184.232.176.184/18")) Then Print "Illegal IP"
End
 
_CanonicalizeCIDR ' do the whole shebang
Param (1) ' IP string
Local (3)
 
b@ = FUNC(_GetIP (a@)) ' get IP address
c@ = FUNC(_GetMask(a@)) ' get the mask
d@ = FUNC(_Canonicalize (b@, c@)) ' canonicalize IP address
' now print the report
Print Show(a@); Tab(20); " -> "; FUNC(_IP(d@, 24)); ".";
Print FUNC(_IP(d@, 16)); "."; FUNC(_IP(d@, 8)); "."; AND(d@, 255); "/"; c@
Return
_IP Param (2) : Return (AND(255, SHL(a@, -b@)))
_Canonicalize Param (2) : Return (AND(a@, FUNC(_MakeMask (b@))))
_GetMask Param (1) : Return (Val(Chop(a@, o)))
_MakeMask Param (1) : Return (NOT(SHL(1, 32 - a@) - 1))
 
_GetIP ' get the IP address
Param (1) ' IP string
Local (1) ' IP number
 
o = 0
b@ = SHL(FUNC(_Parse (a@, Ord("."))), 24)
b@ = OR(b@, SHL(FUNC(_Parse (a@, Ord("."))), 16))
b@ = OR(b@, SHL(FUNC(_Parse (a@, Ord("."))), 8))
b@ = OR(b@, FUNC(_Parse (a@, Ord("/"))))
Return (b@)
 
_Parse ' parse a token
Param (2) ' string, delimiter
Local (1) ' token
 
c@ = Dup ("") ' start with an empty token
 
For o = o to Len (a@) - 1 Until Peek (a@, o) = b@
c@ = Join (c@, Char (Peek (a@, o)))
Next
 
o = o + 1
Return (Val(c@))</syntaxhighlight>
{{Out}}
<pre>36.18.154.103/12 -> 36.16.0.0/12
62.62.197.11/29 -> 62.62.197.8/29
67.137.119.181/4 -> 64.0.0.0/4
161.214.74.0/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18
 
0 OK, 0:388</pre>
 
=={{header|C}}==
This solution uses only the standard library. On POSIX platforms one can use the functions
inet_pton/inet_ntop to parse/format IPv4 addresses.
<langsyntaxhighlight lang="c">#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
Line 274 ⟶ 513:
}
return 0;
}</langsyntaxhighlight>
 
{{out}}
Line 285 ⟶ 524:
184.232.176.184/18 -> 184.232.128.0/18
</pre>
=={{header|C sharp|C#}}==
<syntaxhighlight lang="csharp">using System;
using System.Net;
using System.Linq;
public class Program
{
public static void Main()
{
string[] tests = {
"87.70.141.1/22",
"36.18.154.103/12",
"62.62.197.11/29",
"67.137.119.181/4",
"161.214.74.21/24",
"184.232.176.184/18"
};
foreach (string t in tests) Console.WriteLine($"{t} => {Canonicalize(t)}");
}
static string Canonicalize(string cidr) => CIDR.Parse(cidr).Canonicalize().ToString();
}
 
readonly struct CIDR
{
public readonly IPAddress ip;
public readonly int length;
public static CIDR Parse(string cidr)
{
string[] parts = cidr.Split('/');
return new CIDR(IPAddress.Parse(parts[0]), int.Parse(parts[1]));
}
public CIDR(IPAddress ip, int length) => (this.ip, this.length) = (ip, length);
public CIDR Canonicalize() =>
new CIDR(
new IPAddress(
ToBytes(
ToInt(
ip.GetAddressBytes()
)
& ~((1 << (32 - length)) - 1)
)
),
length
);
private int ToInt(byte[] bytes) => bytes.Aggregate(0, (n, b) => (n << 8) | b);
private byte[] ToBytes(int n)
{
byte[] bytes = new byte[4];
for (int i = 3; i >= 0; i--) {
bytes[i] = (byte)(n & 0xFF);
n >>= 8;
}
return bytes;
}
public override string ToString() => $"{ip}/{length}";
}</syntaxhighlight>
{{out}}
<pre>
87.70.141.1/22 => 87.70.140.0/22
36.18.154.103/12 => 36.16.0.0/12
62.62.197.11/29 => 62.62.197.8/29
67.137.119.181/4 => 64.0.0.0/4
161.214.74.21/24 => 161.214.74.0/24
184.232.176.184/18 => 184.232.128.0/18</pre>
=={{header|C++}}==
<langsyntaxhighlight lang="cpp">#include <cstdint>
#include <iomanip>
#include <iostream>
Line 364 ⟶ 674:
}
return 0;
}</langsyntaxhighlight>
 
{{out}}
<pre>87.70.141.1/22 -> 87.70.140.0/22
<pre>
87.70.141.1/22 -> 87.70.140.0/22
36.18.154.103/12 -> 36.16.0.0/12
62.62.197.11/29 -> 62.62.197.8/29
67.137.119.181/4 -> 64.0.0.0/4
161.214.74.21/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18</pre>
</pre>
 
=={{header|CCommon sharp|C#Lisp}}==
<syntaxhighlight lang="lisp">(defun ip->bit-vector (ip)
<lang csharp>using System;
(flet ((int->bits (int)
using System.Net;
(loop :for i :below 8
using System.Linq;
:collect (if (logbitp i int) 1 0) :into bits
:finally (return (nreverse bits)))))
public class Program
(loop :repeat 4
{
:with start := 0
public static void Main()
:for pos := (position #\. ip :start start)
{
:collect (parse-integer ip :start start :end pos) :into res
string[] tests = {
:while "87.70.141.1/22",pos
:do (setf "36.18.154.103/12",start (1+ pos))
:finally (return (apply #'concatenate 'bit-vector (mapcar #'int->bits res))))))
"62.62.197.11/29",
"67.137.119.181/4",
"161.214.74.21/24",
"184.232.176.184/18"
};
foreach (string t in tests) Console.WriteLine($"{t} => {Canonicalize(t)}");
}
static string Canonicalize(string cidr) => CIDR.Parse(cidr).Canonicalize().ToString();
}
 
(defun bit-vector->ip (vec &optional n)
readonly struct CIDR
(loop :repeat 4
{
:for end :from 8 :by 8
public readonly IPAddress ip;
:for start := (- end 8)
public readonly int length;
:for sub := (subseq vec start end)
:collect (parse-integer (map 'string #'digit-char sub) :radix 2) :into res
public static CIDR Parse(string cidr)
:finally (return (format nil "~{~D~^.~}~@[/~A~]" res n))))
{
 
string[] parts = cidr.Split('/');
(defun canonicalize-cidr (cidr)
return new CIDR(IPAddress.Parse(parts[0]), int.Parse(parts[1]));
(let* ((n (position #\/ cidr))
}
(ip (subseq cidr 0 n))
(sn (parse-integer cidr :start (1+ n)))
public CIDR(IPAddress ip, int length) => (this.ip, this.length) = (ip, length);
(ip* (ip->bit-vector ip))
(canonical-ip (fill ip* 0 :start sn)))
public CIDR Canonicalize() =>
(bit-vector->ip canonical-ip sn)))
new CIDR(
 
new IPAddress(
(loop :for cidr :in '("36.18.154.103/12" "62.62.197.11/29"
ToBytes(
ToInt( "67.137.119.181/4" "161.214.74.21/24"
ip"184.GetAddressBytes(232.176.184/18")
:for ccidr := (canonicalize-cidr cidr)
:do (format t "~& ~((1A~20,T→ << (32~A~%" -cidr lengthccidr)) - 1)
</syntaxhighlight>
)
),
length
);
private int ToInt(byte[] bytes) => bytes.Aggregate(0, (n, b) => (n << 8) | b);
private byte[] ToBytes(int n)
{
byte[] bytes = new byte[4];
for (int i = 3; i >= 0; i--) {
bytes[i] = (byte)(n & 0xFF);
n >>= 8;
}
return bytes;
}
public override string ToString() => $"{ip}/{length}";
}</lang>
{{out}}
<pre>
8736.7018.141154.1103/2212 => 8736.7016.1400.0/2212
3662.1862.154197.10311/1229 => 36 62.1662.0197.08/1229
6267.62137.197119.11181/294 => 6264.620.1970.80/294
67161.137214.11974.18121/424 => 64161.0214.074.0/424
161184.214232.74176.21184/2418 => 161184.214232.74128.0/2418</pre>
=={{header|Cowgol}}==
184.232.176.184/18 => 184.232.128.0/18</pre>
<syntaxhighlight lang="cowgol">include "cowgol.coh";
 
typedef IP is uint32;
 
record CIDR is
ip: IP;
len: uint8;
end record;
 
sub ParseIP(buffer: [uint8]): (result: IP, ptr: [uint8]) is
var parts: uint8 := 4;
var part: int32;
result := 0;
loop
(part, buffer) := AToI(buffer);
parts := parts - 1;
result := result | ((part as IP & 0xFF) << (parts * 8));
if parts == 0 then break;
else buffer := @next buffer;
end if;
end loop;
ptr := buffer;
end sub;
 
sub ParseCIDR(buffer: [uint8], cidr: [CIDR]) is
var len: int32;
(cidr.ip, buffer) := ParseIP(buffer);
(len, buffer) := AToI(@next buffer);
cidr.len := len as uint8;
end sub;
 
sub Canonicalize(cidr: [CIDR]) is
var mask: IP := 0;
var ones: uint8 := cidr.len;
var len: uint8 := 32;
while ones != 0 loop
mask := (mask << 1) | 1;
ones := ones - 1;
len := len - 1;
end loop;
while len != 0 loop;
mask := mask << 1;
len := len - 1;
end loop;
cidr.ip := cidr.ip & mask;
end sub;
 
sub FormatIP(ip: IP, buffer: [uint8]): (ptr: [uint8]) is
ptr := buffer;
ptr := UIToA((ip >> 24) & 0xFF, 10, ptr);
[ptr] := '.';
ptr := UIToA((ip >> 16) & 0xFF, 10, @next ptr);
[ptr] := '.';
ptr := UIToA((ip >> 8) & 0xFF, 10, @next ptr);
[ptr] := '.';
ptr := UIToA(ip & 0xFF, 10, @next ptr);
[ptr] := 0;
end sub;
 
sub FormatCIDR(cidr: [CIDR], buffer: [uint8]) is
buffer := FormatIP(cidr.ip, buffer);
[buffer] := '/';
buffer := UIToA(cidr.len as uint32, 10, @next buffer);
end sub;
 
var buffer: uint8[256];
var string := &buffer[0];
var cidr: CIDR;
 
ParseCIDR("87.70.141.1/22", &cidr);
FormatCIDR(&cidr, string);
 
print("Before canonicalization: ");
print(string);
print_nl();
 
Canonicalize(&cidr);
FormatCIDR(&cidr, string);
 
print(" After canonicalization: ");
print(string);
print_nl();</syntaxhighlight>
{{out}}
<pre>Before canonicalization: 87.70.141.1/22
After canonicalization: 87.70.140.0/22</pre>
=={{header|EasyLang}}==
<syntaxhighlight>
func$ can_cidr s$ .
n[] = number strsplit s$ "./"
if len n[] <> 5
return ""
.
for i to 4
if n[i] < 0 or n[i] > 255
return ""
.
ad = ad * 256 + n[i]
.
if n[5] > 31 or n[5] < 1
return ""
.
mask = bitnot (bitshift 1 (32 - n[5]) - 1)
ad = bitand ad mask
for i to 4
if r$ <> ""
r$ = "." & r$
.
r$ = ad mod 256 & r$
ad = ad div 256
.
return r$ & "/" & n[5]
.
repeat
s$ = input
until s$ = ""
print s$ & " -> " & can_cidr s$
.
#
input_data
87.70.141.1/22
36.18.154.103/12
62.62.197.11/29
67.137.119.181/4
161.214.74.21/24
184.232.176.184/18
 
</syntaxhighlight>
 
=={{header|Factor}}==
{{trans|Ruby}}
{{works with|Factor|0.99 2020-07-03}}
<langsyntaxhighlight lang="factor">USING: command-line formatting grouping io kernel math.parser
namespaces prettyprint sequences splitting ;
IN: rosetta-code.canonicalize-cidr
Line 473 ⟶ 880:
! and output
"%s/%d\n" printf
] each</langsyntaxhighlight>
{{out}}
<pre>
Line 482 ⟶ 889:
=={{header|Go}}==
{{trans|Ruby}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 542 ⟶ 949:
fmt.Printf("%-18s -> %s\n", test, canonicalize(test))
}
}</langsyntaxhighlight>
 
{{out}}
Line 553 ⟶ 960:
184.232.176.184/18 -> 184.232.128.0/18
</pre>
 
=={{header|Hare}}==
<langsyntaxhighlight lang="hare">use fmt;
use net::ip;
use strings;
Line 598 ⟶ 1,004:
0xff & result,
strings::cut(a, "/").1);
};</langsyntaxhighlight>
{{out}}
<pre>
Line 608 ⟶ 1,014:
184.232.176.184/18 => 184.232.128.0/18
</pre>
 
=={{header|Haskell}}==
This is implemented using only libraries found in the base package.
<langsyntaxhighlight lang="haskell">import Control.Monad (guard)
import Data.Bits ((.|.), (.&.), complement, shiftL, shiftR, zeroBits)
import Data.Maybe (listToMaybe)
Line 688 ⟶ 1,093:
test "184.256.176.184/12" -- octet value is too large
test "184.232.176.184/33" -- netmask size is too large
test "184.232.184/18" -- too few components</langsyntaxhighlight>
 
{{out}}
Line 702 ⟶ 1,107:
184.232.184/18 -> invalid CIDR string
</pre>
 
=={{header|J}}==
 
Implementation:
 
<langsyntaxhighlight Jlang="j">cidr=: {{
'a e'=. 0 ".each (y rplc'. ')-.&;:'/'
('/',":e),~rplc&' .'":_8#.\32{.e{.,(8#2)#:a
}}</langsyntaxhighlight>
 
In other words, convert address part to bits, truncate to the network address, extend back to 32 bits and repack into the ascii representation.
Line 716 ⟶ 1,120:
Task examples:
 
<langsyntaxhighlight Jlang="j"> cidr '87.70.141.1/22'
87.70.140.0/22
cidr '36.18.154.103/12'
Line 727 ⟶ 1,131:
161.214.74.0/24
cidr '184.232.176.184/18'
184.232.128.0/18</langsyntaxhighlight>
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">import java.text.MessageFormat;
import java.text.ParseException;
 
Line 795 ⟶ 1,198:
"184.232.176.184/18"
};
}</langsyntaxhighlight>
 
{{out}}
Line 806 ⟶ 1,209:
184.232.176.184/18 -> 184.232.128.0/18
</pre>
 
=={{header|JavaScript}}==
<langsyntaxhighlight lang="javascript">const canonicalize = s => {
 
// Prepare a DataView over a 16 Byte Array buffer.
Line 857 ⟶ 1,259:
'10..55/8',
'10.../8'
].forEach(test)</langsyntaxhighlight>
{{out}}
<pre>
Line 871 ⟶ 1,273:
10..55/8 -> 10.0.0.0/8
10.../8 -> 10.0.0.0/8
</pre>
=={{header|jq}}==
'''Adapted from [[#Wren|Wren]]'''
{{works with|jq}}
'''Also works with gojq, the Go implementation of jq, and with fq'''
 
'''Generic Utilities'''
<syntaxhighlight lang=jq>
# For gojq and fq
def _nwise($n):
def nw: if length <= $n then . else .[0:$n] , (.[$n:] | nw) end;
nw;
 
def lpad($len; $fill): tostring | ($len - length) as $l | ($fill * $l)[:$l] + .;
def lpad($len): lpad($len;" ");
 
# Convert the input integer to a string in the specified base (2 to 36 inclusive)
def convert(base):
def stream:
recurse(if . >= base then ./base|floor else empty end) | . % base ;
[stream] | reverse
| if base < 10 then map(tostring) | join("")
elif base <= 36 then map(if . < 10 then 48 + . else . + 87 end) | implode
else error("base too large")
end;
 
# input string is converted from "base" to an integer, within limits
# of the underlying arithmetic operations, and without error-checking:
def to_i(base):
explode
| reverse
| map(if . > 96 then . - 87 else . - 48 end) # "a" ~ 97 => 10 ~ 87
| reduce .[] as $c
# state: [power, ans]
([1,0]; (.[0] * base) as $b | [$b, .[1] + (.[0] * $c)])
| .[1];
 
</syntaxhighlight>
'''Canonicalize CIDR'''
<syntaxhighlight lang=jq>
# Canonicalize a CIDR block: make sure none of the host bits are set
def canonicalize:
# dotted-decimal / bits in network part
(. / "/") as [$dotted, $bits]
| ($bits | tonumber) as $size
 
# get IP as binary string
| {binary: (($dotted / ".") | map( tonumber | convert(2) | lpad(8; "0") ) | join("") )}
# replace the host part with all zeros
| .binary |= .[0:$size] + "0" * (32 - $size)
 
# convert back to dotted-decimal
| [.binary | explode | _nwise(8) | implode]
| (map( to_i(2) | tostring ) | join(".")) as $canon
 
| $canon + "/" + $bits;
 
def tests:
"87.70.141.1/22",
"36.18.154.103/12",
"62.62.197.11/29",
"67.137.119.181/4",
"161.214.74.21/24",
"184.232.176.184/18"
;
 
tests
| "\(lpad(18)) -> \(canonicalize)"
</syntaxhighlight>
{{output}}
<pre>
87.70.141.1/22 -> 87.70.140.0/22
36.18.154.103/12 -> 36.16.0.0/12
62.62.197.11/29 -> 62.62.197.8/29
67.137.119.181/4 -> 64.0.0.0/4
161.214.74.21/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18
</pre>
 
=={{header|Julia}}==
Julia has a Sockets library as a builtin, which has the types IPv4 and IPv6 for single IP addresses.
<langsyntaxhighlight lang="julia">using Sockets
 
function canonCIDR(cidr::String)
Line 894 ⟶ 1,374:
println(canonCIDR("10..55/8"))
println(canonCIDR("10.../8"))
</langsyntaxhighlight>{{out}}
<pre>
87.70.140.0/22
Line 906 ⟶ 1,386:
</pre>
 
=={{header|Lua}}==
{{libheader|inet}}
<syntaxhighlight lang="lua">inet = require 'inet'
 
test_cases = {
'87.70.141.1/22', '36.18.154.103/12', '62.62.197.11/29', '67.137.119.181/4',
'161.214.74.21/24', '184.232.176.184/18'
}
 
for i, cidr in ipairs(test_cases) do
print( inet(cidr):network() )
end</syntaxhighlight>
 
{{Out}}
<pre>87.70.140.0/22
36.16.0.0/12
62.62.197.8/29
64.0.0.0/4
161.214.74.0/24
184.232.128.0/18</pre>
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">ClearAll[CanonicalizeCIDR]
CanonicalizeCIDR[str_String] := Module[{i, ip, chop, keep, change},
If[StringMatchQ[str, "*.*.*.*/*"],
Line 934 ⟶ 1,434:
CanonicalizeCIDR["67.137.119.181/4"]
CanonicalizeCIDR["161.214.74.21/24"]
CanonicalizeCIDR["184.232.176.184/18"]</langsyntaxhighlight>
{{out}}
<pre>87.70.140.0/22
Line 942 ⟶ 1,442:
161.214.74.0/24
184.232.128.0/18</pre>
 
=={{header|MATLAB}}==
{{trans|Python}}
<syntaxhighlight lang="MATLAB">
clear all;close all;clc;
cidrCanonicalizer();
 
function cidrCanonicalizer
% Main function to test CIDR canonicalization
% Define test cases
testCases = {
'36.18.154.103/12', '36.16.0.0/12';
'62.62.197.11/29', '62.62.197.8/29';
'67.137.119.181/4', '64.0.0.0/4';
'161.214.74.21/24', '161.214.74.0/24';
'184.232.176.184/18', '184.232.128.0/18'
};
% Run test cases
for i = 1:size(testCases, 1)
ip = testCases{i, 1};
expected = testCases{i, 2};
result = canonicalize(ip);
fprintf('%s -> %s\n', ip, result);
assert(strcmp(result, expected));
end
end
 
function result = dottedToInt(dotted)
% Convert dotted IP to integer representation
parts = str2double(strsplit(dotted, '.'));
result = sum(parts .* (256 .^ (3:-1:0)));
end
 
function result = intToDotted(ip)
% Convert integer IP to dotted representation
result = strjoin(arrayfun(@(x) num2str(bitshift(bitand(ip, bitshift(255, x)), -x)), [24 16 8 0], 'UniformOutput', false), '.');
end
 
function result = networkMask(numberOfBits)
% Create a network mask for the given number of bits
result = bitshift((bitshift(1, numberOfBits) - 1), (32 - numberOfBits));
end
 
function result = canonicalize(ip)
% Canonicalize the given CIDR IP
[dotted, networkBits] = strtok(ip, '/');
networkBits = str2double(strrep(networkBits, '/', ''));
i = dottedToInt(dotted);
mask = networkMask(networkBits);
result = strcat(intToDotted(bitand(i, mask)), '/', num2str(networkBits));
end
</syntaxhighlight>
{{out}}
<pre>
36.18.154.103/12 -> 36.16.0.0/12
62.62.197.11/29 -> 62.62.197.8/29
67.137.119.181/4 -> 64.0.0.0/4
161.214.74.21/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18
</pre>
 
=={{header|Nim}}==
Using the IpAddress type from standard module “net”.
<langsyntaxhighlight Nimlang="nim">import net
import strutils
 
Line 1,001 ⟶ 1,563:
# Canonicalize the address and display the result.
ipAddress.canonicalize(nbits)
echo &"{address:<18} ⇢ {ipAddress}/{nbits}"</langsyntaxhighlight>
 
{{out}}
Line 1,010 ⟶ 1,572:
161.214.74.21/24 ⇢ 161.214.74.0/24
184.232.176.184/18 ⇢ 184.232.128.0/18</pre>
 
=={{header|OCaml}}==
<syntaxhighlight lang="ocaml">let mask = function
| _, 0 -> 0l, 0
| a, l -> Int32.(logand (shift_left minus_one (-l land 31)) a), l
 
let str_to_cidr s =
let (<<+) b a = Int32.(add (shift_left b 8) a) in
let recv d c b a l = d <<+ c <<+ b <<+ a, l in
Scanf.sscanf s "%3lu.%3lu.%3lu.%3lu/%2u" recv
 
let cidr_to_str (a, l) =
let addr n =
let dgt = function
| h :: t -> Int32.shift_right_logical h 8 :: Int32.logand h 255l :: t
| l -> l
in
dgt [n] |> dgt |> dgt |> List.map Int32.to_string |> String.concat "."
in
Printf.sprintf "%s/%u" (addr a) l
 
let () =
["87.70.141.1/22"; "36.18.154.103/12"; "62.62.197.11/29"; "67.137.119.181/4"; "161.214.74.21/24"; "184.232.176.184/18"; "10.207.219.251/32"]
|> List.iter (fun s -> str_to_cidr s |> mask |> cidr_to_str |> print_endline)</syntaxhighlight>
{{out}}
<pre>
87.70.140.0/22
36.16.0.0/12
62.62.197.8/29
64.0.0.0/4
161.214.74.0/24
184.232.128.0/18
10.207.219.251/32
</pre>
 
=={{header|Perl}}==
There's a CPAN module for IP address manipulation, <tt>Net::IP</tt>. Unfortunately, it requires a CIDR string to be already in canonical form; otherwise it fails with an "Invalid prefix" error. So we do it manually.
<lang perl>#!/usr/bin/env perl
<syntaxhighlight lang="perl">#!/usr/bin/env perl
use v5.16;
use Socket qw(inet_aton inet_ntoa);
Line 1,037 ⟶ 1,634:
# And output
say "$dotted/$size";
}</langsyntaxhighlight>
{{Out}}
<pre>$ canonicalize_cidr.pl 87.70.141.1/22
87.70.140.0/22</pre>
 
=={{header|Phix}}==
<!--<langsyntaxhighlight Phixlang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> <span style="color: #000080;font-style:italic;">-- (not likely useful)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">canonicalize_cidr</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">cidr</span><span style="color: #0000FF;">)</span>
Line 1,077 ⟶ 1,673:
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%-18s -&gt; %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">,</span><span style="color: #000000;">canonicalize_cidr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ti</span><span style="color: #0000FF;">)})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</langsyntaxhighlight>-->
{{out}}
<pre>
Line 1,087 ⟶ 1,683:
184.232.176.184/18 -> 184.232.128.0/18
</pre>
=={{header|PicoLisp}}==
 
<syntaxhighlight lang="picolisp">(de cidr (S)
(let
(L (rot (mapcar format (split (chop S) "." "/")))
N (++ L)
M
(&
(sum >> (-24 -16 -8 0) L)
(rev 32 (dec (** 2 N))) ) )
(pack
(>> 24 M)
"."
(& 255 (>> 16 M))
"."
(& 255 (>> 8 M))
"."
(& 255 (& 255 M))
"/"
N ) ) )
(let Fmt (18 3 17)
(for A
(quote
"87.70.141.1/22"
"36.18.154.103/12"
"62.62.197.11/29"
"67.137.119.181/4"
"161.214.74.21/24"
"184.232.176.184/18" )
(tab Fmt A "=>" (cidr A)) ) )</syntaxhighlight>
{{out}}
<pre>
87.70.141.1/22 => 87.70.140.0/22
36.18.154.103/12 => 36.16.0.0/12
62.62.197.11/29 => 62.62.197.8/29
67.137.119.181/4 => 64.0.0.0/4
161.214.74.21/24 => 161.214.74.0/24
184.232.176.184/18 => 184.232.128.0/18
</pre>
=={{header|Python}}==
{{trans|Perl}}
<langsyntaxhighlight lang="python">#!/usr/bin/env python
# canonicalize a CIDR block specification:
# make sure none of the host bits are set
Line 1,117 ⟶ 1,750:
canon_dotted = inet_ntoa(pack('!I',
(canon_numeric))) # and then to dotted-decimal
print(f'{canon_dotted}/{size}') # output result</langsyntaxhighlight>
{{Out}}
<pre>$ canonicalize_cidr.py 87.70.141.1/22
87.70.140.0/22</pre>
 
===Bit mask and shift===
<syntaxhighlight lang="python">"""Canonicalize CIDR"""
DIGITS = (24, 16, 8, 0)
 
 
def dotted_to_int(dotted: str) -> int:
digits = [int(digit) for digit in dotted.split(".")]
return sum(a << b for a, b in zip(digits, DIGITS))
 
 
def int_to_dotted(ip: int) -> str:
digits = [(ip & (255 << d)) >> d for d in DIGITS]
return ".".join(str(d) for d in digits)
 
 
def network_mask(number_of_bits: int) -> int:
return ((1 << number_of_bits) - 1) << (32 - number_of_bits)
 
 
def canonicalize(ip: str) -> str:
dotted, network_bits = ip.split("/")
i = dotted_to_int(dotted)
mask = network_mask(int(network_bits))
return int_to_dotted(i & mask) + "/" + network_bits
 
 
TEST_CASES = [
("36.18.154.103/12", "36.16.0.0/12"),
("62.62.197.11/29", "62.62.197.8/29"),
("67.137.119.181/4", "64.0.0.0/4"),
("161.214.74.21/24", "161.214.74.0/24"),
("184.232.176.184/18", "184.232.128.0/18"),
]
 
if __name__ == "__main__":
for ip, expect in TEST_CASES:
rv = canonicalize(ip)
print(f"{ip:<18} -> {rv}")
assert rv == expect
</syntaxhighlight>
 
{{out}}
<pre>
36.18.154.103/12 -> 36.16.0.0/12
62.62.197.11/29 -> 62.62.197.8/29
67.137.119.181/4 -> 64.0.0.0/4
161.214.74.21/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18
</pre>
 
===Using standard library===
 
The <code>ipaddress</code> module was added in Python version 3.3.
 
<syntaxhighlight lang="python">import ipaddress
 
def canonicalize(address: str) -> str:
return str(ipaddress.ip_network(address, strict=False))
 
TEST_CASES = [
("36.18.154.103/12", "36.16.0.0/12"),
("62.62.197.11/29", "62.62.197.8/29"),
("67.137.119.181/4", "64.0.0.0/4"),
("161.214.74.21/24", "161.214.74.0/24"),
("184.232.176.184/18", "184.232.128.0/18"),
]
 
if __name__ == "__main__":
for ip, expect in TEST_CASES:
rv = canonicalize(ip)
print(f"{ip:<18} -> {rv}")
assert rv == expect, expect
</syntaxhighlight>
 
{{out}}
<pre>
36.18.154.103/12 -> 36.16.0.0/12
62.62.197.11/29 -> 62.62.197.8/29
67.137.119.181/4 -> 64.0.0.0/4
161.214.74.21/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18
</pre>
=={{header|Raku}}==
===Using library===
{{libheader|raku-IP-Addr}}
<syntaxhighlight lang="raku" line>use IP::Addr;
for «87.70.141.1/22 36.18.154.103/12 62.62.197.11/29 67.137.119.181/4 161.214.74.21/24 184.232.176.184/18» -> $cidr {
say "$cidr -> $(IP::Addr.new($cidr).network)";
}</syntaxhighlight>
 
===String manipulation===
{{trans|Perl}}
<syntaxhighlight lang="raku" perl6line>#!/usr/bin/env raku
unit sub MAIN(*@cidrs);
 
if !@cidrs {
# canonicalize a CIDR block: make sure none of the host bits are set
# test data
if (!@*ARGS) {
@cidrs = «87.70.141.1/22 36.18.154.103/12 62.62.197.11/29 67.137.119.181/4 161.214.74.21/24 184.232.176.184/18»;
@*ARGS = $*IN.lines;
}
 
for @*ARGScidrs -> $cidr {
say "$cidr -> $(canonicalize $cidr)";
}
 
# canonicalize a CIDR block: make sure none of the host bits are set
sub canonicalize($cidr) {
# dotted-decimal / bits in network part
my ($dotted, $size) = $cidr.split(: '/');
 
# get network part of the IP as binary string
my $binary = $dotted.split('.').map(*».fmt("'%08b")').join.substr(0, $size);
 
# Replace theAdd host part with all zeroes
$binary.substr-rw($size) ~= 0 x (32 - $size);
 
# Convert back to dotted-decimal
my $canon = $binary.comb(8).map(*.join».parse-base(2)).join(: '.');
 
# And output
say "$canon/$size";
}</langsyntaxhighlight>
 
{{Out}}
<pre>$ canonicalize_cidr.raku 87.70.141.1/22 -> 87.70.140.0/22
36.18.154.103/12 -> 36.16.0.0/12
87.70.140.0/22</pre>
62.62.197.11/29 -> 62.62.197.8/29
67.137.119.181/4 -> 64.0.0.0/4
161.214.74.21/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18</pre>
 
===Bit mask and shift===
<syntaxhighlight lang="raku" perl6line># canonicalize a IP4 CIDR block
sub CIDR-IP4-canonicalize ($address) {
constant @mask = 24, 16, 8, 0;
Line 1,189 ⟶ 1,920:
printf "CIDR: %18s Routing prefix: %s/%s\n", $_, |.&CIDR-IP4-canonicalize
for @*ARGS || @tests;</langsyntaxhighlight>
{{out}}
<pre>CIDR: 87.70.141.1/22 Routing prefix: 87.70.140.0/22
Line 1,204 ⟶ 1,935:
CIDR: 10.11.12.13/8 Routing prefix: 10.0.0.0/8
CIDR: 10.../8 Routing prefix: 10.0.0.0/8</pre>
 
=={{header|REXX}}==
<langsyntaxhighlight lang="rexx">/*REXX pgm canonicalizes IPv4 addresses that are in CIDR notation (dotted─dec/network).*/
parse arg a . /*obtain optional argument from the CL.*/
if a=='' | a=="," then a= '87.70.141.1/22' , /*Not specified? Then use the defaults*/
Line 1,237 ⟶ 1,967:
/*──────────────────────────────────────────────────────────────────────────────────────*/
b2d: return x2d( b2x( arg(1) ) ) + 0 /*convert binary ───► decimal number.*/
d2b: return x2b( d2x( arg(1) ) ) + 0 /* " decimal ───► binary " */</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default input:}}
<pre>
Line 1,257 ⟶ 1,987:
original IPv4 address: 184.232.176.184/18
canonicalized address: 184.232.128.0/18
</pre>
=={{header|RPL}}==
RPL has hundreds of built-in functions, but strangely a few limited ones for bit handling. There is no <code>>></code> operator, so shifting left an integer by n bits shall be done through a loop: <code> 1 n '''START''' SL '''NEXT'''</code>
{| class="wikitable"
! RPL code
! Comment
|-
|
DUP SIZE "" 1 ROT '''FOR''' j
OVER j j SUB DUP "0" ≥ OVER "9" ≤ AND SWAP " "
IFTE + '''NEXT'''
SWAP DROP STR→ → nbits
≪ SWAP ROT 4 ROLL
32 STWS 1 3 '''START''' #100h * + '''NEXT'''
#FFFFFFFF 1 32 nbits - '''START''' SL '''NEXT''' AND
1 3 '''START''' DUP SRB SWAP OVER SLB - SWAP '''NEXT'''
B→R →STR 1 3 '''START''' "." + SWAP B→R →STR + '''NEXT'''
"/" + nbits →STR +
≫ ≫ ‘<span style="color:blue">CANON</span>’ STO
|
<span style="color:blue">CANON</span> ''( "nn.nn.nn.nn/bits" → "nn.nn.nn.nn/nbits" )
Scan input string
Replace non-numerical chars by spaces
Drop input string, parse addresses to stack - except # bits
Reverse stack order
Consolidate numbers into a 32-bit number
Set and apply mask
Break 32-bit number into 4 in the stack
Make a IP address with the 4 numbers
add # bits
|}
≪ { "36.18.154.103/12" "62.62.197.11/29" "67.137.119.181/4" "161.214.74.21/24" "184.232.176.184/18" } → t
≪ 1 5 '''FOR''' j t j GET <span style="color:blue">CANON</span> '''NEXT'''
≫ ≫ ‘<span style="color:blue">TASK</span>’ STO
{{out}}
<pre>
5: "36.16.0.0/12"
4: "62.62.197.8/29"
3: "64.0.0.0/4"
2: "161.214.74.0/24"
1: "184.232.128.0/18"
</pre>
 
Line 1,263 ⟶ 2,037:
{{trans|Raku}}
 
<langsyntaxhighlight lang="ruby">#!/usr/bin/env ruby
 
# canonicalize a CIDR block: make sure none of the host bits are set
Line 1,287 ⟶ 2,061:
# And output
puts "#{canon}/#{size}"
end</langsyntaxhighlight>
 
{{Out}}
<pre>$ canonicalize_cidr.rb 87.70.141.1/22
87.70.140.0/22</pre>
===Built in===
<syntaxhighlight lang="ruby">
require "ipaddr"
tests = ["87.70.141.1/22", "36.18.154.103/12", "62.62.197.11/29",
"67.137.119.181/4", "161.214.74.21/24", "184.232.176.184/18"]
tests.each do |str|
ia = IPAddr.new(str)
puts "#{ia}/#{ia.prefix}"
end
</syntaxhighlight>
{{out}}
<pre>
87.70.140.0/22
36.16.0.0/12
62.62.197.8/29
64.0.0.0/4
161.214.74.0/24
184.232.128.0/18</pre>
 
=={{header|Rust}}==
<langsyntaxhighlight Rustlang="rust">use std::net::Ipv4Addr;
 
fn canonical_cidr(cidr: &str) -> Result<String, &str> {
Line 1,332 ⟶ 2,126:
fn main() {
println!("{}", canonical_cidr("127.1.2.3/24").unwrap());
}</langsyntaxhighlight>
 
=={{header|Scala}}==
{{trans|Java}}
<syntaxhighlight lang="Scala">
import java.text.MessageFormat
 
object CanonicalizeCIDR extends App {
case class CIDR(address: Int, maskLength: Int) {
override def toString: String = {
val a = (address >> 24) & 0xFF
val b = (address >> 16) & 0xFF
val c = (address >> 8) & 0xFF
val d = address & 0xFF
MessageFormat.format(CIDR.format, a.asInstanceOf[AnyRef], b.asInstanceOf[AnyRef], c.asInstanceOf[AnyRef], d.asInstanceOf[AnyRef], maskLength.asInstanceOf[AnyRef])
}
}
 
object CIDR {
private val format = "{0,number,integer}.{1,number,integer}.{2,number,integer}.{3,number,integer}/{4,number,integer}"
 
def apply(str: String): CIDR = {
val args = new MessageFormat(format).parse(str)
val address = args.take(4).foldLeft(0) { (acc, arg) =>
val a = arg.asInstanceOf[Number].intValue()
require(a >= 0 && a <= 255, "Invalid IP address")
(acc << 8) + a
}
val maskLength = args(4).asInstanceOf[Number].intValue()
require(maskLength >= 1 && maskLength <= 32, "Invalid mask length")
val mask = ~((1 << (32 - maskLength)) - 1)
new CIDR(address & mask, maskLength)
}
}
 
val tests = Array(
"87.70.141.1/22",
"36.18.154.103/12",
"62.62.197.11/29",
"67.137.119.181/4",
"161.214.74.21/24",
"184.232.176.184/18"
)
 
tests.foreach { test =>
try {
val cidr = CIDR(test)
println(f"$test%-18s -> $cidr")
} catch {
case ex: Exception => println(s"Error parsing '$test': ${ex.getLocalizedMessage}")
}
}
}
</syntaxhighlight>
{{out}}
<pre>
87.70.141.1/22 -> 87.70.140.0/22
36.18.154.103/12 -> 36.16.0.0/12
62.62.197.11/29 -> 62.62.197.8/29
67.137.119.181/4 -> 64.0.0.0/4
161.214.74.21/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18
 
</pre>
 
=={{header|SNOBOL}}==
<syntaxhighlight lang="snobol">* Pattern to match any number of digits
D = SPAN('0123456789')
 
* Convert a dotted-decimal IP address to an integer
DEFINE('INET_ATON(Str),B3,B2,B1,B0') :(END_INET_ATON)
INET_ATON Str D . B3 '.' D . B2 '.' D . B1 '.' D . B0 :F(FRETURN)
INET_ATON = B3 * 16777216 + B2 * 65536 + B1 * 256 + B0 :(RETURN)
END_INET_ATON
 
* Convert an integer to dotted-decimal
DEFINE('INET_NTOA(Addr),Count,Byte') :(END_INET_NTOA)
INET_NTOA Count = 0
N2ALOOP Byte = REMDR(Addr,256)
Addr = (Addr - Byte) / 256
INET_NTOA = Byte '.' INET_NTOA
Count = Count + 1
LT(Count,4) :S(N2ALOOP)
INET_NTOA '.' RPOS(0) = '' :(RETURN)
END_INET_NTOA
 
* Convert a CIDR range to canonical form
DEFINE('FIXCIDR(Cidr),IP,Net,In,Host,Count,Pow,Out,Bit') :(END_FIXCIDR)
FIXCIDR Cidr Arb . IP '/' D . Net :F(FRETURN)
In = INET_ATON(IP)
Host = 32 - Net
 
* Compute result of treating all bits in the host part as 0
Out = 0
Count = 0
Pow = 1
MASKLOOP Bit = REMDR(In, 2)
In = (In - Bit) / 2
Out = GE(Count, Host) Out + Bit * Pow
Count = Count + 1
Pow = Pow * 2
LT(Count, 32) :S(MASKLOOP)
 
* Convert back to dotted-decimal
FIXCIDR = INET_NTOA(Out) '/' Net :(RETURN)
END_FIXCIDR
 
OUTPUT = FIXCIDR('87.70.141.1/22')
OUTPUT = FIXCIDR('36.18.154.103/12')
OUTPUT = FIXCIDR('62.62.197.11/29')
OUTPUT = FIXCIDR('67.137.119.181/4')
OUTPUT = FIXCIDR('161.214.74.21/24')
OUTPUT = FIXCIDR('184.232.176.184/18')
END</syntaxhighlight>
 
{{Out}}
<pre>87.70.140.0/22
36.16.0.0/12
62.62.197.8/29
64.0.0.0/4
161.214.74.0/24
184.232.128.0/18</pre>
 
=={{header|Swift}}==
{{trans|Python}}
<syntaxhighlight lang="Swift">
import Foundation
 
func dottedToInt(_ dotted: String) -> UInt32 {
let digits = dotted.split(separator: ".").map { UInt32($0)! }
return digits.enumerated().reduce(0) { $0 + ($1.element << (24 - $1.offset * 8)) }
}
 
func intToDotted(_ ip: UInt32) -> String {
let digits = [24, 16, 8, 0].map { (ip & (255 << $0)) >> $0 }
return digits.map { String($0) }.joined(separator: ".")
}
 
func networkMask(_ numberOfBits: Int) -> UInt32 {
// Explicitly use UInt32 for bitwise operations
return UInt32((1 << numberOfBits) - 1) << (32 - numberOfBits)
}
 
func canonicalize(_ ip: String) -> String {
let parts = ip.split(separator: "/")
let dotted = String(parts[0])
let networkBits = Int(parts[1])!
let i = dottedToInt(dotted)
let mask = networkMask(networkBits)
return "\(intToDotted(i & mask))/\(networkBits)"
}
 
let testCases = [
("36.18.154.103/12", "36.16.0.0/12"),
("62.62.197.11/29", "62.62.197.8/29"),
("67.137.119.181/4", "64.0.0.0/4"),
("161.214.74.21/24", "161.214.74.0/24"),
("184.232.176.184/18", "184.232.128.0/18"),
]
 
for testCase in testCases {
let (ip, expect) = testCase
let result = canonicalize(ip)
print("\(ip) -> \(result)")
assert(result == expect, "Test failed for \(ip)")
}
</syntaxhighlight>
{{out}}
<pre>
36.18.154.103/12 -> 36.16.0.0/12
62.62.197.11/29 -> 62.62.197.8/29
67.137.119.181/4 -> 64.0.0.0/4
161.214.74.21/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18
 
</pre>
 
 
=={{header|Tcl}}==
{{trans|Python}}
<syntaxhighlight lang="Tcl">
# Canonicalize CIDR in Tcl
 
# Convert dotted IP address to integer
proc dotted_to_int {dotted} {
set digits [split $dotted .]
set result 0
foreach digit $digits {
set result [expr {$result * 256 + $digit}]
}
return $result
}
 
# Convert integer IP address to dotted format
proc int_to_dotted {ip} {
set result {}
for {set i 3} {$i >= 0} {incr i -1} {
lappend result [expr {($ip >> ($i * 8)) & 0xFF}]
}
return [join $result .]
}
 
# Calculate network mask
proc network_mask {number_of_bits} {
return [expr {(1 << $number_of_bits) - 1 << (32 - $number_of_bits)}]
}
 
# Canonicalize IP address
proc canonicalize {ip} {
regexp {^(.*)/(.*)$} $ip -> dotted network_bits
set i [dotted_to_int $dotted]
set mask [network_mask $network_bits]
return [int_to_dotted [expr {$i & $mask}]]/$network_bits
}
 
# Test cases
set test_cases {
{"36.18.154.103/12" "36.16.0.0/12"}
{"62.62.197.11/29" "62.62.197.8/29"}
{"67.137.119.181/4" "64.0.0.0/4"}
{"161.214.74.21/24" "161.214.74.0/24"}
{"184.232.176.184/18" "184.232.128.0/18"}
}
 
# Main execution
foreach test $test_cases {
foreach {ip expect} $test {}
set rv [canonicalize $ip]
puts "$ip -> $rv"
if {$rv ne $expect} {
error "Test failed: $rv != $expect"
}
}
</syntaxhighlight>
{{out}}
<pre>
36.18.154.103/12 -> 36.16.0.0/12
62.62.197.11/29 -> 62.62.197.8/29
67.137.119.181/4 -> 64.0.0.0/4
161.214.74.21/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18
 
</pre>
 
 
=={{header|TXR}}==
 
The <code>inaddr-str</code> function in TXR Lisp parses IPv4 addresses, converting them to a <code>sockaddr-in</code> structure. If there is a slash notation present, it is recognized. The prefix value is validated and stored in the structure as the <code>prefix</code> value, and the numeric address is canonicalized to clear the irrelevant bits. Thus, the solution looks like this:
 
<syntaxhighlight lang="txrlisp">(defun cidr-canon (str)
(let ((a (inaddr-str str)))
`@(str-inaddr a.addr)/@{a.prefix}`))</syntaxhighlight>
 
Furthermore, the prefix notation can be condensed by removing unnecessary zeros. That is to say, <code>10.1.2.3/16</code> can be not just canonicalized to strip the irrelevant bits, but then shortened to <code>10.1/16</code>.
 
The built-in function <code>inaddr-str-net</code> will produce this condensed prefix notation:
 
<syntaxhighlight lang="txrlisp">(defun cidr-canon (str)
(let ((a (inaddr-str str)))
(str-inaddr-net a.addr a.prefix)))</syntaxhighlight>
 
This can be written using the <code>flow</code> macro:
 
<syntaxhighlight lang="txrlisp">(defun cidr-canon (str)
(flow str
inaddr-str
(str-inaddr-net @1.addr @1.prefix)))</syntaxhighlight>
 
=={{header|UNIX Shell}}==
{{works with|Bourne Again SHell}}
{{works with|Korn Shell}}
{{works with|Zsh}}
<syntaxhighlight lang="bash">function inet_aton {
typeset -i addr byte
typeset -a bytes
if [[ -n $BASH_VERSION ]]; then
IFS=. read -a bytes <<<"$1"
elif [[ -n $ZSH_VERSION ]]; then
IFS=. bytes=($=1)
else
IFS=. bytes=($1)
fi
addr=0
for byte in "${bytes[@]}"; do
(( addr = 256 * addr + byte ))
done
printf '%s\n' "$addr"
}
 
function inet_ntoa {
typeset -i addr=$1
typeset dotted i
for (( i=0; i<4; ++i )); do
dotted=$(( addr & 255 ))${dotted:+.$dotted}
(( addr >>= 8 ))
done
printf '%s\n' "$dotted"
}
 
function canonicalize_cidr {
typeset ip prefix fixed
typeset -i netmask addr
while (( $# )); do
IFS=/ read ip prefix <<<"$1"
netmask=$(( (-1 << (32-prefix)) & -1 ))
addr=$(inet_aton "$ip")
fixed=$(( addr & netmask ))
printf '%s/%s\n' "$(inet_ntoa $fixed)" "$prefix"
shift
done
}
 
# demo code
if (( ! $# )); then
set -- 36.18.154.103/12 62.62.197.11/29 67.137.119.181/4 161.214.74.21/24 184.232.176.184/18
fi
canonicalize_cidr "$@"</syntaxhighlight>
{{Out}}
<pre>36.16.0.0/12
62.62.197.8/29
64.0.0.0/4
161.214.74.0/24
184.232.128.0/18</pre>
 
=={{header|Wren}}==
Line 1,338 ⟶ 2,455:
{{libheader|Wren-fmt}}
{{libheader|Wren-str}}
<langsyntaxhighlight ecmascriptlang="wren">import "./fmt" for Fmt, Conv
import "./str" for Str
 
// canonicalize a CIDR block: make sure none of the host bits are set
Line 1,373 ⟶ 2,490:
for (test in tests) {
Fmt.print("$-18s -> $s", test, canonicalize.call(test))
}</langsyntaxhighlight>
 
{{out}}
Line 1,383 ⟶ 2,500:
161.214.74.21/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18
</pre>
 
=={{header|XPL0}}==
Device 8 is a 256-byte input/output buffer that provides a convenient
means for converting between ASCII and binary representations of numbers.
<syntaxhighlight lang "XPL0">proc Canonicalize(IPAddr);
char IPAddr;
int N, I, HostBits;
[Text(0, IPAddr);
Text(0, " ^i-> "); \^i = tab
OpenO(8);
Text(8, IPAddr); \ASCII out
OpenI(8);
N:= 0;
for I:= 0 to 3 do
N:= N<<8 + IntIn(8); \binary in
HostBits:= IntIn(8);
N:= N & -1<<(32-HostBits);
for I:= 3 downto 0 do
[IntOut(0, N>>(I*8) & $FF);
ChOut(0, if I = 0 then ^/ else ^.);
];
IntOut(0, HostBits);
CrLf(0);
];
 
int IPAddrs, I;
[IPAddrs:= [
"87.70.141.1/22",
"36.18.154.103/12",
"62.62.197.11/29",
"67.137.119.181/4",
"161.214.74.21/24",
"184.232.176.184/18" ];
for I:= 0 to 6-1 do
Canonicalize(IPAddrs(I));
]</syntaxhighlight>
{{out}}
<pre>
87.70.141.1/22 -> 87.70.140.0/22
36.18.154.103/12 -> 36.16.0.0/12
62.62.197.11/29 -> 62.62.197.8/29
67.137.119.181/4 -> 64.0.0.0/4
161.214.74.21/24 -> 161.214.74.0/24
184.232.176.184/18 -> 184.232.128.0/18
</pre>
337

edits