RosettaCodeData/Task/Parse-an-IP-Address/Elixir/parse-an-ip-address.ex
2025-08-11 18:05:26 -07:00

83 lines
2 KiB
Elixir

#!/usr/bin/env elixir
defmodule IPParse do
@moduledoc """
IP address parser that handles IPv4 and IPv6 addresses with optional ports
"""
def main(args \\ []) do
addresses = if Enum.empty?(args), do: data(), else: args
for addr <- addresses do
print(addr, parse(addr))
end
System.halt(0)
end
@spec parse(String.t()) ::
{String.t(), binary(), String.t()} |
{String.t(), binary()}
def parse("[" <> addr0) do
case String.split(addr0, "]", parts: 2) do
[addr] ->
{"IPv6", to_hex(:inet.parse_address(String.to_charlist(addr)))}
[addr, ":" <> port] ->
{"IPv6", to_hex(:inet.parse_address(String.to_charlist(addr))), port}
end
end
def parse(addr0) do
case :inet.parse_address(String.to_charlist(addr0)) do
{:error, :einval} ->
[addr, port] = String.split(addr0, ":", parts: 2)
{"IPv4", to_hex(:inet.parse_address(String.to_charlist(addr))), port}
{:ok, v6_addr} ->
{"IPv6", to_hex({:ok, v6_addr})}
end
end
@spec to_hex({:ok, :inet.ip_address()}) :: binary()
def to_hex({:ok, {a, b, c, d}}) do
Base.encode16(<<a::8, b::8, c::8, d::8>>)
end
def to_hex({:ok, {a, b, c, d, e, f, g, h}}) do
Base.encode16(<<a::16, b::16, c::16, d::16, e::16, f::16, g::16, h::16>>)
end
def print(input, {family, hex, port}) do
IO.puts("Input: #{input}")
IO.puts("Family: #{family}")
IO.puts("Hex: #{hex}")
IO.puts("Port: #{port}")
IO.puts("")
end
def print(input, {family, hex}) do
IO.puts("Input: #{input}")
IO.puts("Family: #{family}")
IO.puts("Hex: #{hex}")
IO.puts("")
end
defp data do
[
"127.0.0.1",
"127.0.0.1:80",
"::ffff:127.0.0.1",
"::1",
"[::1]:80",
"1::80",
"2605:2700:0:3::4713:93e3",
"[2605:2700:0:3::4713:93e3]:80"
]
end
end
# Run the main function if this script is executed directly
if __ENV__.file == Path.absname(:escript.script_name()) do
IPParse.main(System.argv())
end