Canonicalize CIDR: Difference between revisions

Add Swift implementation
(Clean up task description a bit.)
(Add Swift implementation)
 
(20 intermediate revisions by 14 users not shown)
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 196:
FI
OD
END</langsyntaxhighlight>
{{out}}
<pre>
Line 206:
184.232.176.184/18 -> 184.232.128.0/18
</pre>
 
=={{header|APL}}==
{{works with|Dyalog APL}}
<langsyntaxhighlight lang="apl"> canonicalize←{
nums←(2⊃⎕VFI)¨(~⍵∊'./')⊆⍵
ip len←(4↑nums)(5⊃nums)
Line 216 ⟶ 215:
ip←(4/256)⊤2⊥ip
(1↓∊'.',¨⍕¨ip),'/',⍕len
}</langsyntaxhighlight>
{{out}}
<langsyntaxhighlight lang="apl"> canonicalize '87.70.141.1/22'
87.70.140.0/22</langsyntaxhighlight>
 
=={{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 287 ⟶ 513:
}
return 0;
}</langsyntaxhighlight>
 
{{out}}
Line 298 ⟶ 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 377 ⟶ 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|C sharp|C#}}==
<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}";
}</lang>
{{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|Commodore BASIC}}==
<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</lang>
 
{{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|Common Lisp}}==
<langsyntaxhighlight lang="lisp">(defun ip->bit-vector (ip)
(flet ((int->bits (int)
(loop :for i :below 8
Line 555 ⟶ 719:
:for ccidr := (canonicalize-cidr cidr)
:do (format t "~&~A~20,T→ ~A~%" cidr ccidr))
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 563 ⟶ 727:
161.214.74.21/24 → 161.214.74.0/24
184.232.176.184/18 → 184.232.128.0/18</pre>
 
=={{header|Cowgol}}==
<langsyntaxhighlight lang="cowgol">include "cowgol.coh";
 
typedef IP is uint32;
Line 646 ⟶ 809:
print(" After canonicalization: ");
print(string);
print_nl();</langsyntaxhighlight>
{{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 675 ⟶ 880:
! and output
"%s/%d\n" printf
] each</langsyntaxhighlight>
{{out}}
<pre>
Line 684 ⟶ 889:
=={{header|Go}}==
{{trans|Ruby}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 744 ⟶ 949:
fmt.Printf("%-18s -> %s\n", test, canonicalize(test))
}
}</langsyntaxhighlight>
 
{{out}}
Line 755 ⟶ 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 800 ⟶ 1,004:
0xff & result,
strings::cut(a, "/").1);
};</langsyntaxhighlight>
{{out}}
<pre>
Line 810 ⟶ 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 890 ⟶ 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 904 ⟶ 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 918 ⟶ 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 929 ⟶ 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 997 ⟶ 1,198:
"184.232.176.184/18"
};
}</langsyntaxhighlight>
 
{{out}}
Line 1,008 ⟶ 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 1,059 ⟶ 1,259:
'10..55/8',
'10.../8'
].forEach(test)</langsyntaxhighlight>
{{out}}
<pre>
Line 1,073 ⟶ 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 1,096 ⟶ 1,374:
println(canonCIDR("10..55/8"))
println(canonCIDR("10.../8"))
</langsyntaxhighlight>{{out}}
<pre>
87.70.140.0/22
Line 1,110 ⟶ 1,388:
=={{header|Lua}}==
{{libheader|inet}}
<langsyntaxhighlight lang="lua">inet = require 'inet'
 
test_cases = {
Line 1,119 ⟶ 1,397:
for i, cidr in ipairs(test_cases) do
print( inet(cidr):network() )
end</langsyntaxhighlight>
 
{{Out}}
Line 1,128 ⟶ 1,406:
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 1,157 ⟶ 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 1,165 ⟶ 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,224 ⟶ 1,563:
# Canonicalize the address and display the result.
ipAddress.canonicalize(nbits)
echo &"{address:<18} ⇢ {ipAddress}/{nbits}"</langsyntaxhighlight>
 
{{out}}
Line 1,233 ⟶ 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.
<langsyntaxhighlight lang="perl">#!/usr/bin/env perl
use v5.16;
use Socket qw(inet_aton inet_ntoa);
Line 1,261 ⟶ 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,301 ⟶ 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,311 ⟶ 1,683:
184.232.176.184/18 -> 184.232.128.0/18
</pre>
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(de cidr (S)
(let
(L (rot (mapcar format (split (chop S) "." "/")))
Line 1,340 ⟶ 1,711:
"161.214.74.21/24"
"184.232.176.184/18" )
(tab Fmt A "=>" (cidr A)) ) )</langsyntaxhighlight>
{{out}}
<pre>
Line 1,350 ⟶ 1,721:
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,380 ⟶ 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
Line 1,386 ⟶ 1,756:
 
===Bit mask and shift===
<langsyntaxhighlight lang="python">"""Canonicalize CIDR"""
DIGITS = (24, 16, 8, 0)
 
Line 1,424 ⟶ 1,794:
print(f"{ip:<18} -> {rv}")
assert rv == expect
</syntaxhighlight>
</lang>
 
{{out}}
Line 1,435 ⟶ 1,805:
</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" perl6line>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)";
}</langsyntaxhighlight>
 
===String manipulation===
{{trans|Perl}}
<syntaxhighlight lang="raku" perl6line>#!/usr/bin/env raku
unit sub MAIN(*@cidrs);
 
Line 1,473 ⟶ 1,875:
# And output
say "$canon/$size";
}</langsyntaxhighlight>
 
{{Out}}
Line 1,484 ⟶ 1,886:
 
===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,518 ⟶ 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,533 ⟶ 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,566 ⟶ 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,586 ⟶ 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,592 ⟶ 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,616 ⟶ 2,061:
# And output
puts "#{canon}/#{size}"
end</langsyntaxhighlight>
 
{{Out}}
Line 1,622 ⟶ 2,067:
87.70.140.0/22</pre>
===Built in===
<langsyntaxhighlight lang="ruby">
require "ipaddr"
Line 1,632 ⟶ 2,077:
puts "#{ia}/#{ia.prefix}"
end
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,643 ⟶ 2,088:
 
=={{header|Rust}}==
<langsyntaxhighlight Rustlang="rust">use std::net::Ipv4Addr;
 
fn canonical_cidr(cidr: &str) -> Result<String, &str> {
Line 1,681 ⟶ 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}}==
<langsyntaxhighlight lang="snobol">* Pattern to match any number of digits
D = SPAN('0123456789')
 
Line 1,731 ⟶ 2,239:
OUTPUT = FIXCIDR('161.214.74.21/24')
OUTPUT = FIXCIDR('184.232.176.184/18')
END</langsyntaxhighlight>
 
{{Out}}
Line 1,740 ⟶ 2,248:
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}}==
Line 1,745 ⟶ 2,399:
{{works with|Korn Shell}}
{{works with|Zsh}}
<langsyntaxhighlight lang="bash">function inet_aton {
typeset -i addr byte
typeset -a bytes
Line 1,789 ⟶ 2,443:
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 "$@"</langsyntaxhighlight>
{{Out}}
<pre>36.16.0.0/12
Line 1,801 ⟶ 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,836 ⟶ 2,490:
for (test in tests) {
Fmt.print("$-18s -> $s", test, canonicalize.call(test))
}</langsyntaxhighlight>
 
{{out}}
Line 1,846 ⟶ 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