Canonicalize CIDR: Difference between revisions

Content added Content deleted
(Python alternative)
Line 1,384: Line 1,384:
<pre>$ canonicalize_cidr.py 87.70.141.1/22
<pre>$ canonicalize_cidr.py 87.70.141.1/22
87.70.140.0/22</pre>
87.70.140.0/22</pre>

===Bit mask and shift===
<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
</lang>

{{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}}==
=={{header|Raku}}==