Parse an IP Address: Difference between revisions

From Rosetta Code
Content added Content deleted
 
(46 intermediate revisions by 23 users not shown)
Line 1: Line 1:
{{task}}
{{task}}The purpose of this task is to demonstrate parsing of text-format IP addresses, using IPv4 and IPv6.
The purpose of this task is to demonstrate parsing of text-format IP addresses, using IPv4 and IPv6.


Taking the following as inputs:
Taking the following as inputs:
{| border="1" cellspacing="0" cellpadding=2
::: {| border="5" cellspacing="0" cellpadding=2
|-
|-
|127.0.0.1
|127.0.0.1
Line 23: Line 25:
|}
|}


Emit each described IP address as a hexadecimal integer representing the address, the address space, and the port number specified, if any. In languages where variant result types are clumsy, the result should be ipv4 or ipv6 address number, something which says which address space was represented, port number and something that says if the port was specified.


;Task:
For example 127.0.0.1 has the address number 7F000001 (2130706433 decimal) in the ipv4 address space. ::ffff:127.0.0.1 represents the same address in the ipv6 address space where it has the address number FFFF7F000001 (281472812449793 decimal). Meanwhile ::1 has address number 1 and serves the same purpose in the ipv6 address space that 127.0.0.1 serves in the ipv4 address space.
Emit each described IP address as a hexadecimal integer representing the address, the address space, and the port number specified, if any.

In languages where variant result types are clumsy, the result should be ipv4 or ipv6 address number, something which says which address space was represented, port number and something that says if the port was specified.


;Example:
'''127.0.0.1'''   has the address number   '''7F000001'''   (2130706433 decimal)
in the ipv4 address space.

'''::ffff:127.0.0.1'''   represents the same address in the ipv6 address space where it has the
address number   '''FFFF7F000001'''   (281472812449793 decimal).

'''::1'''   has address number   '''1'''   and serves the same purpose in the ipv6 address
space that   '''127.0.0.1'''   serves in the ipv4 address space.
<br><br>

=={{header|AutoHotkey}}==
<syntaxhighlight lang="autohotkey">ParseIP(Address){
return InStr(A_LoopField, ".") ? IPv4(Address) : IPv6(Address)
}

IPv4(Address){
for i, v in StrSplit(Address, "."){
x := StrSplit(v, ":")
num .= SubStr("00" . Format("{:X}", x.1), -1)
port := x.2 ? x.2 : ""
}
return [num, port]
}

IPv6(Address){
for i, v in StrSplit(Address, "]")
if i = 1
for j, x in StrSplit(LTrim(v, "[:"), ":")
num .= x = "" ? "00000000" : SubStr("0000" x, -3)
else
port := LTrim(v, ":")
return [SubStr("00000000000000000000000000000000" num, -31), port]
}</syntaxhighlight>
Examples:<syntaxhighlight lang="autohotkey">data =
(
127.0.0.1
127.0.0.1:80
::1
[::1]:80
2605:2700:0:3::4713:93e3
[2605:2700:0:3::4713:93e3]:80
)

output := ""
loop, parse, data, `n, `r
{
x := ParseIP(A_LoopField)
output .= "input = " A_LoopField "`t>`t" x.1 . (x.2 ? " port : " x.2 : "") "`n"
}
MsgBox % output
return</syntaxhighlight>
{{out}}<pre>
input = 127.0.0.1 > 7F000001
input = 127.0.0.1:80 > 7F000001 port : 80
input = ::1 > 00000000000000000000000000000001
input = [::1]:80 > 00000000000000000000000000000001 port : 80
input = 2605:2700:0:3::4713:93e3 > 260527000000000300000000471393e3
input = [2605:2700:0:3::4713:93e3]:80 > 260527000000000300000000471393e3 port : 80
</pre>


=={{header|C}}==
=={{header|C}}==
{{libheader|C standard library}}
{{libheader|C standard library}}
<syntaxhighlight lang="c">
<lang C>
#include <string.h>
#include <string.h>
#include <memory.h>
#include <memory.h>
Line 36: Line 102:
static unsigned int _parseDecimal ( const char** pchCursor )
static unsigned int _parseDecimal ( const char** pchCursor )
{
{
unsigned int nVal = 0;
unsigned int nVal = 0;
char chNow;
char chNow;
while ( chNow = **pchCursor, chNow >= '0' && chNow <= '9' )
while ( chNow = **pchCursor, chNow >= '0' && chNow <= '9' )
{
{
//shift digit in
//shift digit in
nVal *= 10;
nVal *= 10;
nVal += chNow - '0';
nVal += chNow - '0';


++*pchCursor;
++*pchCursor;
}
}
return nVal;
return nVal;
}
}


Line 53: Line 119:
static unsigned int _parseHex ( const char** pchCursor )
static unsigned int _parseHex ( const char** pchCursor )
{
{
unsigned int nVal = 0;
unsigned int nVal = 0;
char chNow;
char chNow;
while ( chNow = **pchCursor & 0x5f, //(collapses case, but mutilates digits)
while ( chNow = **pchCursor & 0x5f, //(collapses case, but mutilates digits)
(chNow >= ('0'&0x5f) && chNow <= ('9'&0x5f)) ||
(chNow >= ('0'&0x5f) && chNow <= ('9'&0x5f)) ||
(chNow >= 'A' && chNow <= 'F')
(chNow >= 'A' && chNow <= 'F')
)
)
{
{
unsigned char nybbleValue;
unsigned char nybbleValue;
chNow -= 0x10; //scootch digital values down; hex now offset by x31
chNow -= 0x10; //scootch digital values down; hex now offset by x31
nybbleValue = ( chNow > 9 ? chNow - (0x31-0x0a) : chNow );
nybbleValue = ( chNow > 9 ? chNow - (0x31-0x0a) : chNow );
//shift nybble in
//shift nybble in
nVal <<= 4;
nVal <<= 4;
nVal += nybbleValue;
nVal += nybbleValue;


++*pchCursor;
++*pchCursor;
}
}
return nVal;
return nVal;
}
}


Line 86: Line 152:
//Note: the binary address and integer port are in network order.
//Note: the binary address and integer port are in network order.
int ParseIPv4OrIPv6 ( const char** ppszText,
int ParseIPv4OrIPv6 ( const char** ppszText,
unsigned char* abyAddr, int* pnPort, int* pbIsIPv6 )
unsigned char* abyAddr, int* pnPort, int* pbIsIPv6 )
{
{
unsigned char* abyAddrLocal;
unsigned char* abyAddrLocal;
unsigned char abyDummyAddr[16];
unsigned char abyDummyAddr[16];


//find first colon, dot, and open bracket
//find first colon, dot, and open bracket
const char* pchColon = strchr ( *ppszText, ':' );
const char* pchColon = strchr ( *ppszText, ':' );
const char* pchDot = strchr ( *ppszText, '.' );
const char* pchDot = strchr ( *ppszText, '.' );
const char* pchOpenBracket = strchr ( *ppszText, '[' );
const char* pchOpenBracket = strchr ( *ppszText, '[' );
const char* pchCloseBracket = NULL;
const char* pchCloseBracket = NULL;




//we'll consider this to (probably) be IPv6 if we find an open
//we'll consider this to (probably) be IPv6 if we find an open
//bracket, or an absence of dots, or if there is a colon, and it
//bracket, or an absence of dots, or if there is a colon, and it
//precedes any dots that may or may not be there
//precedes any dots that may or may not be there
int bIsIPv6local = NULL != pchOpenBracket || NULL == pchDot ||
int bIsIPv6local = NULL != pchOpenBracket || NULL == pchDot ||
( NULL != pchColon && ( NULL == pchDot || pchColon < pchDot ) );
( NULL != pchColon && ( NULL == pchDot || pchColon < pchDot ) );
//OK, now do a little further sanity check our initial guess...
//OK, now do a little further sanity check our initial guess...
if ( bIsIPv6local )
if ( bIsIPv6local )
{
{
//if open bracket, then must have close bracket that follows somewhere
//if open bracket, then must have close bracket that follows somewhere
pchCloseBracket = strchr ( *ppszText, ']' );
pchCloseBracket = strchr ( *ppszText, ']' );
if ( NULL != pchOpenBracket && ( NULL == pchCloseBracket ||
if ( NULL != pchOpenBracket && ( NULL == pchCloseBracket ||
pchCloseBracket < pchOpenBracket ) )
pchCloseBracket < pchOpenBracket ) )
return 0;
return 0;
}
}
else //probably ipv4
else //probably ipv4
{
{
//dots must exist, and precede any colons
//dots must exist, and precede any colons
if ( NULL == pchDot || ( NULL != pchColon && pchColon < pchDot ) )
if ( NULL == pchDot || ( NULL != pchColon && pchColon < pchDot ) )
return 0;
return 0;
}
}


//we figured out this much so far....
//we figured out this much so far....
if ( NULL != pbIsIPv6 )
if ( NULL != pbIsIPv6 )
*pbIsIPv6 = bIsIPv6local;
*pbIsIPv6 = bIsIPv6local;
//especially for IPv6 (where we will be decompressing and validating)
//especially for IPv6 (where we will be decompressing and validating)
//we really need to have a working buffer even if the caller didn't
//we really need to have a working buffer even if the caller didn't
//care about the results.
//care about the results.
abyAddrLocal = abyAddr; //prefer to use the caller's
abyAddrLocal = abyAddr; //prefer to use the caller's
if ( NULL == abyAddrLocal ) //but use a dummy if we must
if ( NULL == abyAddrLocal ) //but use a dummy if we must
abyAddrLocal = abyDummyAddr;
abyAddrLocal = abyDummyAddr;


//OK, there should be no correctly formed strings which are miscategorized,
//OK, there should be no correctly formed strings which are miscategorized,
//and now any format errors will be found out as we continue parsing
//and now any format errors will be found out as we continue parsing
//according to plan.
//according to plan.
if ( ! bIsIPv6local ) //try to parse as IPv4
if ( ! bIsIPv6local ) //try to parse as IPv4
{
{
//4 dotted quad decimal; optional port if there is a colon
//4 dotted quad decimal; optional port if there is a colon
//since there are just 4, and because the last one can be terminated
//since there are just 4, and because the last one can be terminated
//differently, I'm just going to unroll any potential loop.
//differently, I'm just going to unroll any potential loop.
unsigned char* pbyAddrCursor = abyAddrLocal;
unsigned char* pbyAddrCursor = abyAddrLocal;
unsigned int nVal;
unsigned int nVal;
const char* pszTextBefore = *ppszText;
const char* pszTextBefore = *ppszText;
nVal =_parseDecimal ( ppszText ); //get first val
nVal =_parseDecimal ( ppszText ); //get first val
if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText ) //must be in range and followed by dot and nonempty
if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText ) //must be in range and followed by dot and nonempty
return 0;
return 0;
*(pbyAddrCursor++) = (unsigned char) nVal; //stick it in addr
*(pbyAddrCursor++) = (unsigned char) nVal; //stick it in addr
++(*ppszText); //past the dot
++(*ppszText); //past the dot


pszTextBefore = *ppszText;
pszTextBefore = *ppszText;
nVal =_parseDecimal ( ppszText ); //get second val
nVal =_parseDecimal ( ppszText ); //get second val
if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )
if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )
return 0;
return 0;
*(pbyAddrCursor++) = (unsigned char) nVal;
*(pbyAddrCursor++) = (unsigned char) nVal;
++(*ppszText); //past the dot
++(*ppszText); //past the dot


pszTextBefore = *ppszText;
pszTextBefore = *ppszText;
nVal =_parseDecimal ( ppszText ); //get third val
nVal =_parseDecimal ( ppszText ); //get third val
if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )
if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )
return 0;
return 0;
*(pbyAddrCursor++) = (unsigned char) nVal;
*(pbyAddrCursor++) = (unsigned char) nVal;
++(*ppszText); //past the dot
++(*ppszText); //past the dot


pszTextBefore = *ppszText;
pszTextBefore = *ppszText;
nVal =_parseDecimal ( ppszText ); //get fourth val
nVal =_parseDecimal ( ppszText ); //get fourth val
if ( nVal > 255 || pszTextBefore == *ppszText ) //(we can terminate this one in several ways)
if ( nVal > 255 || pszTextBefore == *ppszText ) //(we can terminate this one in several ways)
return 0;
return 0;
*(pbyAddrCursor++) = (unsigned char) nVal;
*(pbyAddrCursor++) = (unsigned char) nVal;


if ( ':' == **ppszText && NULL != pnPort ) //have port part, and we want it
if ( ':' == **ppszText && NULL != pnPort ) //have port part, and we want it
{
{
unsigned short usPortNetwork; //save value in network order
unsigned short usPortNetwork; //save value in network order
++(*ppszText); //past the colon
++(*ppszText); //past the colon
pszTextBefore = *ppszText;
pszTextBefore = *ppszText;
nVal =_parseDecimal ( ppszText );
nVal =_parseDecimal ( ppszText );
if ( nVal > 65535 || pszTextBefore == *ppszText )
if ( nVal > 65535 || pszTextBefore == *ppszText )
return 0;
return 0;
((unsigned char*)&usPortNetwork)[0] = ( nVal & 0xff00 ) >> 8;
((unsigned char*)&usPortNetwork)[0] = ( nVal & 0xff00 ) >> 8;
((unsigned char*)&usPortNetwork)[1] = ( nVal & 0xff );
((unsigned char*)&usPortNetwork)[1] = ( nVal & 0xff );
*pnPort = usPortNetwork;
*pnPort = usPortNetwork;
return 1;
return 1;
}
}
else //finished just with ip address
else //finished just with ip address
{
{
if ( NULL != pnPort )
if ( NULL != pnPort )
*pnPort = 0; //indicate we have no port part
*pnPort = 0; //indicate we have no port part
return 1;
return 1;
}
}
}
}
else //try to parse as IPv6
else //try to parse as IPv6
{
{
unsigned char* pbyAddrCursor;
unsigned char* pbyAddrCursor;
unsigned char* pbyZerosLoc;
unsigned char* pbyZerosLoc;
int bIPv4Detected;
int bIPv4Detected;
int nIdx;
int nIdx;
//up to 8 16-bit hex quantities, separated by colons, with at most one
//up to 8 16-bit hex quantities, separated by colons, with at most one
//empty quantity, acting as a stretchy run of zeroes. optional port
//empty quantity, acting as a stretchy run of zeroes. optional port
//if there are brackets followed by colon and decimal port number.
//if there are brackets followed by colon and decimal port number.
//A further form allows an ipv4 dotted quad instead of the last two
//A further form allows an ipv4 dotted quad instead of the last two
//16-bit quantities, but only if in the ipv4 space ::ffff:x:x .
//16-bit quantities, but only if in the ipv4 space ::ffff:x:x .
if ( NULL != pchOpenBracket ) //start past the open bracket, if it exists
if ( NULL != pchOpenBracket ) //start past the open bracket, if it exists
*ppszText = pchOpenBracket + 1;
*ppszText = pchOpenBracket + 1;
pbyAddrCursor = abyAddrLocal;
pbyAddrCursor = abyAddrLocal;
pbyZerosLoc = NULL; //if we find a 'zero compression' location
pbyZerosLoc = NULL; //if we find a 'zero compression' location
bIPv4Detected = 0;
bIPv4Detected = 0;
for ( nIdx = 0; nIdx < 8; ++nIdx ) //we've got up to 8 of these, so we will use a loop
for ( nIdx = 0; nIdx < 8; ++nIdx ) //we've got up to 8 of these, so we will use a loop
{
{
const char* pszTextBefore = *ppszText;
const char* pszTextBefore = *ppszText;
unsigned nVal =_parseHex ( ppszText ); //get value; these are hex
unsigned nVal =_parseHex ( ppszText ); //get value; these are hex
if ( pszTextBefore == *ppszText ) //if empty, we are zero compressing; note the loc
if ( pszTextBefore == *ppszText ) //if empty, we are zero compressing; note the loc
{
{
if ( NULL != pbyZerosLoc ) //there can be only one!
if ( NULL != pbyZerosLoc ) //there can be only one!
{
{
//unless it's a terminal empty field, then this is OK, it just means we're done with the host part
//unless it's a terminal empty field, then this is OK, it just means we're done with the host part
if ( pbyZerosLoc == pbyAddrCursor )
if ( pbyZerosLoc == pbyAddrCursor )
{
{
--nIdx;
--nIdx;
break;
break;
}
}
return 0; //otherwise, it's a format error
return 0; //otherwise, it's a format error
}
}
if ( ':' != **ppszText ) //empty field can only be via :
if ( ':' != **ppszText ) //empty field can only be via :
return 0;
return 0;
if ( 0 == nIdx ) //leading zero compression requires an extra peek, and adjustment
if ( 0 == nIdx ) //leading zero compression requires an extra peek, and adjustment
{
{
++(*ppszText);
++(*ppszText);
if ( ':' != **ppszText )
if ( ':' != **ppszText )
return 0;
return 0;
}
}


pbyZerosLoc = pbyAddrCursor;
pbyZerosLoc = pbyAddrCursor;
++(*ppszText);
++(*ppszText);
}
}
else
else
{
{
if ( '.' == **ppszText ) //special case of ipv4 convenience notation
if ( '.' == **ppszText ) //special case of ipv4 convenience notation
{
{
//who knows how to parse ipv4? we do!
//who knows how to parse ipv4? we do!
const char* pszTextlocal = pszTextBefore; //back it up
const char* pszTextlocal = pszTextBefore; //back it up
unsigned char abyAddrlocal[16];
unsigned char abyAddrlocal[16];
int bIsIPv6local;
int bIsIPv6local;
int bParseResultlocal = ParseIPv4OrIPv6 ( &pszTextlocal, abyAddrlocal, NULL, &bIsIPv6local );
int bParseResultlocal = ParseIPv4OrIPv6 ( &pszTextlocal, abyAddrlocal, NULL, &bIsIPv6local );
*ppszText = pszTextlocal; //success or fail, remember the terminating char
*ppszText = pszTextlocal; //success or fail, remember the terminating char
if ( ! bParseResultlocal || bIsIPv6local ) //must parse and must be ipv4
if ( ! bParseResultlocal || bIsIPv6local ) //must parse and must be ipv4
return 0;
return 0;
//transfer addrlocal into the present location
//transfer addrlocal into the present location
*(pbyAddrCursor++) = abyAddrlocal[0];
*(pbyAddrCursor++) = abyAddrlocal[0];
*(pbyAddrCursor++) = abyAddrlocal[1];
*(pbyAddrCursor++) = abyAddrlocal[1];
*(pbyAddrCursor++) = abyAddrlocal[2];
*(pbyAddrCursor++) = abyAddrlocal[2];
*(pbyAddrCursor++) = abyAddrlocal[3];
*(pbyAddrCursor++) = abyAddrlocal[3];
++nIdx; //pretend like we took another short, since the ipv4 effectively is two shorts
++nIdx; //pretend like we took another short, since the ipv4 effectively is two shorts
bIPv4Detected = 1; //remember how we got here for further validation later
bIPv4Detected = 1; //remember how we got here for further validation later
break; //totally done with address
break; //totally done with address
}
}


if ( nVal > 65535 ) //must be 16 bit quantity
if ( nVal > 65535 ) //must be 16 bit quantity
return 0;
return 0;
*(pbyAddrCursor++) = nVal >> 8; //transfer in network order
*(pbyAddrCursor++) = nVal >> 8; //transfer in network order
*(pbyAddrCursor++) = nVal & 0xff;
*(pbyAddrCursor++) = nVal & 0xff;
if ( ':' == **ppszText ) //typical case inside; carry on
if ( ':' == **ppszText ) //typical case inside; carry on
{
{
++(*ppszText);
++(*ppszText);
}
}
else //some other terminating character; done with this parsing parts
else //some other terminating character; done with this parsing parts
{
{
break;
break;
}
}
}
}
}
}
//handle any zero compression we found
//handle any zero compression we found
if ( NULL != pbyZerosLoc )
if ( NULL != pbyZerosLoc )
{
{
int nHead = (int)( pbyZerosLoc - abyAddrLocal ); //how much before zero compression
int nHead = (int)( pbyZerosLoc - abyAddrLocal ); //how much before zero compression
int nTail = nIdx * 2 - (int)( pbyZerosLoc - abyAddrLocal ); //how much after zero compression
int nTail = nIdx * 2 - (int)( pbyZerosLoc - abyAddrLocal ); //how much after zero compression
int nZeros = 16 - nTail - nHead; //how much zeros
int nZeros = 16 - nTail - nHead; //how much zeros
memmove ( &abyAddrLocal[16-nTail], pbyZerosLoc, nTail ); //scootch stuff down
memmove ( &abyAddrLocal[16-nTail], pbyZerosLoc, nTail ); //scootch stuff down
memset ( pbyZerosLoc, 0, nZeros ); //clear the compressed zeros
memset ( pbyZerosLoc, 0, nZeros ); //clear the compressed zeros
}
}
//validation of ipv4 subspace ::ffff:x.x
//validation of ipv4 subspace ::ffff:x.x
if ( bIPv4Detected )
if ( bIPv4Detected )
{
{
static const unsigned char abyPfx[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
static const unsigned char abyPfx[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
if ( 0 != memcmp ( abyAddrLocal, abyPfx, sizeof(abyPfx) ) )
if ( 0 != memcmp ( abyAddrLocal, abyPfx, sizeof(abyPfx) ) )
return 0;
return 0;
}
}


//close bracket
//close bracket
if ( NULL != pchOpenBracket )
if ( NULL != pchOpenBracket )
{
{
if ( ']' != **ppszText )
if ( ']' != **ppszText )
return 0;
return 0;
++(*ppszText);
++(*ppszText);
}
}


if ( ':' == **ppszText && NULL != pnPort ) //have port part, and we want it
if ( ':' == **ppszText && NULL != pnPort ) //have port part, and we want it
{
{
const char* pszTextBefore;
const char* pszTextBefore;
unsigned int nVal;
unsigned int nVal;
unsigned short usPortNetwork; //save value in network order
unsigned short usPortNetwork; //save value in network order
++(*ppszText); //past the colon
++(*ppszText); //past the colon
pszTextBefore = *ppszText;
pszTextBefore = *ppszText;
pszTextBefore = *ppszText;
pszTextBefore = *ppszText;
nVal =_parseDecimal ( ppszText );
nVal =_parseDecimal ( ppszText );
if ( nVal > 65535 || pszTextBefore == *ppszText )
if ( nVal > 65535 || pszTextBefore == *ppszText )
return 0;
return 0;
((unsigned char*)&usPortNetwork)[0] = ( nVal & 0xff00 ) >> 8;
((unsigned char*)&usPortNetwork)[0] = ( nVal & 0xff00 ) >> 8;
((unsigned char*)&usPortNetwork)[1] = ( nVal & 0xff );
((unsigned char*)&usPortNetwork)[1] = ( nVal & 0xff );
*pnPort = usPortNetwork;
*pnPort = usPortNetwork;
return 1;
return 1;
}
}
else //finished just with ip address
else //finished just with ip address
{
{
if ( NULL != pnPort )
if ( NULL != pnPort )
*pnPort = 0; //indicate we have no port part
*pnPort = 0; //indicate we have no port part
return 1;
return 1;
}
}
}
}


}
}
Line 323: Line 389:
//simple version if we want don't care about knowing how much we ate
//simple version if we want don't care about knowing how much we ate
int ParseIPv4OrIPv6_2 ( const char* pszText,
int ParseIPv4OrIPv6_2 ( const char* pszText,
unsigned char* abyAddr, int* pnPort, int* pbIsIPv6 )
unsigned char* abyAddr, int* pnPort, int* pbIsIPv6 )
{
{
const char* pszTextLocal = pszText;
const char* pszTextLocal = pszText;
return ParseIPv4OrIPv6 ( &pszTextLocal, abyAddr, pnPort, pbIsIPv6);
return ParseIPv4OrIPv6 ( &pszTextLocal, abyAddr, pnPort, pbIsIPv6);
}
}
</syntaxhighlight>
</lang>
Test:
Test:
<syntaxhighlight lang="c">
<lang C>
#include <stdio.h>
#include <stdio.h>


Line 338: Line 404:
unsigned short htons ( unsigned short us )
unsigned short htons ( unsigned short us )
{
{
return ( ((unsigned char*)&us)[0] << 8 ) + ((unsigned char*)&us)[1];
return ( ((unsigned char*)&us)[0] << 8 ) + ((unsigned char*)&us)[1];
}
}


void dumpbin ( unsigned char* pbyBin, int nLen )
void dumpbin ( unsigned char* pbyBin, int nLen )
{
{
int i;
int i;
for ( i = 0; i < nLen; ++i )
for ( i = 0; i < nLen; ++i )
{
{
printf ( "%02x", pbyBin[i] );
printf ( "%02x", pbyBin[i] );
}
}
}
}


Line 353: Line 419:
void testcase ( const char* pszTest )
void testcase ( const char* pszTest )
{
{
unsigned char abyAddr[16];
unsigned char abyAddr[16];
int bIsIPv6;
int bIsIPv6;
int nPort;
int nPort;
int bSuccess;
int bSuccess;


printf ( "Test case '%s'\n", pszTest );
printf ( "Test case '%s'\n", pszTest );
const char* pszTextCursor = pszTest;
const char* pszTextCursor = pszTest;
bSuccess = ParseIPv4OrIPv6 ( &pszTextCursor, abyAddr, &nPort, &bIsIPv6 );
bSuccess = ParseIPv4OrIPv6 ( &pszTextCursor, abyAddr, &nPort, &bIsIPv6 );
if ( ! bSuccess )
if ( ! bSuccess )
{
{
printf ( "parse failed, at about index %d; rest: '%s'\n", pszTextCursor - pszTest, pszTextCursor );
printf ( "parse failed, at about index %d; rest: '%s'\n", pszTextCursor - pszTest, pszTextCursor );
return;
return;
}
}
printf ( "addr: " );
printf ( "addr: " );
dumpbin ( abyAddr, bIsIPv6 ? 16 : 4 );
dumpbin ( abyAddr, bIsIPv6 ? 16 : 4 );
printf ( "\n" );
printf ( "\n" );
if ( 0 == nPort )
if ( 0 == nPort )
printf ( "port absent" );
printf ( "port absent" );
else
else
printf ( "port: %d", htons ( nPort ) );
printf ( "port: %d", htons ( nPort ) );
printf ( "\n\n" );
printf ( "\n\n" );
}
}


Line 382: Line 448:
int main ( int argc, char* argv[] )
int main ( int argc, char* argv[] )
{
{
//The "localhost" IPv4 address
//The "localhost" IPv4 address
testcase ( "127.0.0.1" );
testcase ( "127.0.0.1" );
//The "localhost" IPv4 address, with a specified port (80)
//The "localhost" IPv4 address, with a specified port (80)
testcase ( "127.0.0.1:80" );
testcase ( "127.0.0.1:80" );
//The "localhost" IPv6 address
//The "localhost" IPv6 address
testcase ( "::1" );
testcase ( "::1" );
//The "localhost" IPv6 address, with a specified port (80)
//The "localhost" IPv6 address, with a specified port (80)
testcase ( "[::1]:80" );
testcase ( "[::1]:80" );
//Rosetta Code's primary server's public IPv6 address
//Rosetta Code's primary server's public IPv6 address
testcase ( "2605:2700:0:3::4713:93e3" );
testcase ( "2605:2700:0:3::4713:93e3" );
//Rosetta Code's primary server's public IPv6 address, with a specified port (80)
//Rosetta Code's primary server's public IPv6 address, with a specified port (80)
testcase ( "[2605:2700:0:3::4713:93e3]:80" );
testcase ( "[2605:2700:0:3::4713:93e3]:80" );
//ipv4 space
//ipv4 space
testcase ( "::ffff:192.168.173.22" );
testcase ( "::ffff:192.168.173.22" );
//ipv4 space with port
//ipv4 space with port
testcase ( "[::ffff:192.168.173.22]:80" );
testcase ( "[::ffff:192.168.173.22]:80" );
//trailing compression
//trailing compression
testcase ( "1::" );
testcase ( "1::" );
//trailing compression with port
//trailing compression with port
testcase ( "[1::]:80" );
testcase ( "[1::]:80" );
//'any' address compression
//'any' address compression
testcase ( "::" );
testcase ( "::" );
//'any' address compression with port
//'any' address compression with port
testcase ( "[::]:80" );
testcase ( "[::]:80" );
return 0;
return 0;
}
}
</syntaxhighlight>
</lang>


Output:
Output:
Line 465: Line 531:
</pre>
</pre>


===POSIX===
{{libheader|POSIX}}
The task is a bit easier on POSIX platforms where we can use the function inet_pton
to parse IP addresses. This approach will also work on Microsoft Windows with some
minor changes.
<syntaxhighlight lang="c">#include <arpa/inet.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

typedef struct ip_address_tag {
union {
uint8_t address_v6[16];
uint32_t address_v4;
} address;
uint16_t family;
uint16_t port;
} ip_address_t;

bool parse_ipv4_address(const char* input, ip_address_t* result) {
struct in_addr addr;
if (inet_pton(AF_INET, input, &addr) == 1) {
result->family = AF_INET;
result->address.address_v4 = ntohl(addr.s_addr);
result->port = 0;
return true;
}
return false;
}

bool parse_ipv6_address(const char* input, ip_address_t* result) {
struct in6_addr addr;
if (inet_pton(AF_INET6, input, &addr) == 1) {
result->family = AF_INET6;
memcpy(result->address.address_v6, addr.s6_addr, 16);
result->port = 0;
return true;
}
return false;
}

uint16_t parse_port_number(const char* str) {
char* eptr;
unsigned long port = strtoul(str, &eptr, 10);
if (port > 0 && *eptr == '\0' && port <= UINT16_MAX)
return (uint16_t)port;
return 0;
}

//
// Parse an IP address and port from the given input string.
// Returns false if the input is not valid.
//
// Valid formats are:
// [ipv6_address]:port
// ipv4_address:port
// ipv4_address
// ipv6_address
//
bool parse_address(const char* input, ip_address_t* result) {
char* ptr = strrchr(input, ':');
if (ptr != NULL && ptr > input) {
uint16_t port = parse_port_number(ptr + 1);
if (port > 0) {
bool success = false;
char* copy = strdup(input);
if (copy == NULL)
return false;
int index = ptr - input;
copy[index] = '\0';
if (copy[index - 1] == ']' && copy[0] == '[') {
copy[index - 1] = '\0';
if (parse_ipv6_address(copy + 1, result))
success = true;
} else if (parse_ipv4_address(copy, result)) {
success = true;
}
free(copy);
if (success) {
result->port = port;
return true;
}
}
}
return parse_ipv6_address(input, result)
|| parse_ipv4_address(input, result);
}

void test_parse_address(const char* input) {
printf("input: %s\n", input);
ip_address_t result;
if (parse_address(input, &result)) {
printf("address family: %s\n",
result.family == AF_INET ? "IPv4" : "IPv6");
if (result.family == AF_INET)
printf("address: %X", result.address.address_v4);
else if (result.family == AF_INET6) {
printf("address: ");
for (int i = 0; i < 16; ++i)
printf("%02X", (unsigned int)result.address.address_v6[i]);
}
printf("\n");
if (result.port > 0)
printf("port: %hu\n", result.port);
else
printf("port not specified\n");
} else {
printf("Parsing failed.\n");
}
printf("\n");
}

int main() {
test_parse_address("127.0.0.1");
test_parse_address("127.0.0.1:80");
test_parse_address("::ffff:127.0.0.1");
test_parse_address("::1");
test_parse_address("[::1]:80");
test_parse_address("1::80");
test_parse_address("2605:2700:0:3::4713:93e3");
test_parse_address("[2605:2700:0:3::4713:93e3]:80");
return 0;
}</syntaxhighlight>

{{out}}
<pre>
input: 127.0.0.1
address family: IPv4
address: 7F000001
port not specified

input: 127.0.0.1:80
address family: IPv4
address: 7F000001
port: 80

input: ::ffff:127.0.0.1
address family: IPv6
address: 00000000000000000000FFFF7F000001
port not specified

input: ::1
address family: IPv6
address: 00000000000000000000000000000001
port not specified

input: [::1]:80
address family: IPv6
address: 00000000000000000000000000000001
port: 80

input: 1::80
address family: IPv6
address: 00010000000000000000000000000080
port not specified

input: 2605:2700:0:3::4713:93e3
address family: IPv6
address: 260527000000000300000000471393E3
port not specified

input: [2605:2700:0:3::4713:93e3]:80
address family: IPv6
address: 260527000000000300000000471393E3
port: 80

</pre>

=={{header|C#}}==
{{trans|Java}}
<syntaxhighlight lang="C#">
using System;
using System.Text.RegularExpressions;
using System.Text;

class ParseIPAddress
{
private static readonly Regex IPV4_PAT = new Regex(@"^(\d+)\.(\d+)\.(\d+)\.(\d+)(?::(\d+)){0,1}$");
private static readonly Regex IPV6_DOUBL_COL_PAT = new Regex(@"^\[{0,1}([0-9a-f:]*)::([0-9a-f:]*)(?:\]:(\d+)){0,1}$");
private static readonly Regex IPV6_PAT;

static ParseIPAddress()
{
string ipv6Pattern = @"^\[{0,1}";
for (int i = 1; i <= 7; i++)
{
ipv6Pattern += @"([0-9a-f]+):";
}
ipv6Pattern += @"([0-9a-f]+)(?:\]:(\d+)){0,1}$";
IPV6_PAT = new Regex(ipv6Pattern);
}

static void Main(string[] args)
{
string[] tests = new string[] { "192.168.0.1", "127.0.0.1", "256.0.0.1", "127.0.0.1:80", "::1", "[::1]:80", "[32e::12f]:80", "2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80", "2001:db8:85a3:0:0:8a2e:370:7334" };
Console.WriteLine(String.Format("{0,-40} {1,-32} {2}", "Test Case", "Hex Address", "Port"));
foreach (var ip in tests)
{
try
{
string[] parsed = ParseIP(ip);
Console.WriteLine(String.Format("{0,-40} {1,-32} {2}", ip, parsed[0], parsed[1]));
}
catch (ArgumentException e)
{
Console.WriteLine(String.Format("{0,-40} Invalid address: {1}", ip, e.Message));
}
}
}

private static string[] ParseIP(string ip)
{
string hex = "";
string port = "";

// IPV4
Match ipv4Matcher = IPV4_PAT.Match(ip);
if (ipv4Matcher.Success)
{
for (int i = 1; i <= 4; i++)
{
hex += ToHex4(ipv4Matcher.Groups[i].Value);
}
if (ipv4Matcher.Groups[5].Success)
{
port = ipv4Matcher.Groups[5].Value;
}
return new string[] { hex, port };
}

// IPV6, double colon
Match ipv6DoubleColonMatcher = IPV6_DOUBL_COL_PAT.Match(ip);
if (ipv6DoubleColonMatcher.Success)
{
string p1 = ipv6DoubleColonMatcher.Groups[1].Value;
if (p1 == "")
{
p1 = "0";
}
string p2 = ipv6DoubleColonMatcher.Groups[2].Value;
if (p2 == "")
{
p2 = "0";
}
ip = p1 + GetZero(8 - NumCount(p1) - NumCount(p2)) + p2;
if (ipv6DoubleColonMatcher.Groups[3].Success)
{
ip = "[" + ip + "]:" + ipv6DoubleColonMatcher.Groups[3].Value;
}
}

// IPV6
Match ipv6Matcher = IPV6_PAT.Match(ip);
if (ipv6Matcher.Success)
{
for (int i = 1; i <= 8; i++)
{
hex += String.Format("{0,4}", ToHex6(ipv6Matcher.Groups[i].Value)).Replace(" ", "0");
}
if (ipv6Matcher.Groups[9].Success)
{
port = ipv6Matcher.Groups[9].Value;
}
return new string[] { hex, port };
}

throw new ArgumentException("ERROR 103: Unknown address: " + ip);
}

private static int NumCount(string s)
{
return s.Split(':').Length;
}

private static string GetZero(int count)
{
StringBuilder sb = new StringBuilder();
sb.Append(":");
while (count > 0)
{
sb.Append("0:");
count--;
}
return sb.ToString();
}

private static string ToHex4(string s)
{
int val = int.Parse(s);
if (val < 0 || val > 255)
{
throw new ArgumentException("ERROR 101: Invalid value : " + s);
}
return val.ToString("X2");
}

private static string ToHex6(string s)
{
int val = int.Parse(s, System.Globalization.NumberStyles.HexNumber);
if (val < 0 || val > 65536)
{
throw new ArgumentException("ERROR 102: Invalid hex value : " + s);
}
return s;
}
}
</syntaxhighlight>
{{out}}
<pre>
Test Case Hex Address Port
192.168.0.1 C0A80001
127.0.0.1 7F000001
256.0.0.1 Invalid address: ERROR 101: Invalid value : 256
127.0.0.1:80 7F000001 80
::1 00000000000000000000000000000001
[::1]:80 00000000000000000000000000000001 80
[32e::12f]:80 032e000000000000000000000000012f 80
2605:2700:0:3::4713:93e3 260527000000000300000000471393e3
[2605:2700:0:3::4713:93e3]:80 260527000000000300000000471393e3 80
2001:db8:85a3:0:0:8a2e:370:7334 20010db885a3000000008a2e03707334

</pre>

=={{header|C++}}==
{{libheader|Boost}}
<syntaxhighlight lang="cpp">#include <boost/asio/ip/address.hpp>
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <limits>
#include <string>

using boost::asio::ip::address;
using boost::asio::ip::address_v4;
using boost::asio::ip::address_v6;
using boost::asio::ip::make_address;
using boost::asio::ip::make_address_v4;
using boost::asio::ip::make_address_v6;

template<typename uint>
bool parse_int(const std::string& str, int base, uint& n) {
try {
size_t pos = 0;
unsigned long u = stoul(str, &pos, base);
if (pos != str.length() || u > std::numeric_limits<uint>::max())
return false;
n = static_cast<uint>(u);
return true;
} catch (const std::exception& ex) {
return false;
}
}

//
// Parse an IP address and port from the given input string.
//
// Throws an exception if the input is not valid.
//
// Valid formats are:
// [ipv6_address]:port
// ipv4_address:port
// ipv4_address
// ipv6_address
//
void parse_ip_address_and_port(const std::string& input, address& addr, uint16_t& port) {
size_t pos = input.rfind(':');
if (pos != std::string::npos && pos > 1 && pos + 1 < input.length()
&& parse_int(input.substr(pos + 1), 10, port) && port > 0) {
if (input[0] == '[' && input[pos - 1] == ']') {
// square brackets so can only be an IPv6 address
addr = make_address_v6(input.substr(1, pos - 2));
return;
} else {
try {
// IPv4 address + port?
addr = make_address_v4(input.substr(0, pos));
return;
} catch (const std::exception& ex) {
// nope, might be an IPv6 address
}
}
}
port = 0;
addr = make_address(input);
}

void print_address_and_port(const address& addr, uint16_t port) {
std::cout << std::hex << std::uppercase << std::setfill('0');
if (addr.is_v4()) {
address_v4 addr4 = addr.to_v4();
std::cout << "address family: IPv4\n";
std::cout << "address number: " << std::setw(8) << addr4.to_uint() << '\n';
} else if (addr.is_v6()) {
address_v6 addr6 = addr.to_v6();
address_v6::bytes_type bytes(addr6.to_bytes());
std::cout << "address family: IPv6\n";
std::cout << "address number: ";
for (unsigned char byte : bytes)
std::cout << std::setw(2) << static_cast<unsigned int>(byte);
std::cout << '\n';
}
if (port != 0)
std::cout << "port: " << std::dec << port << '\n';
else
std::cout << "port not specified\n";
}

void test(const std::string& input) {
std::cout << "input: " << input << '\n';
try {
address addr;
uint16_t port = 0;
parse_ip_address_and_port(input, addr, port);
print_address_and_port(addr, port);
} catch (const std::exception& ex) {
std::cout << "parsing failed\n";
}
std::cout << '\n';
}

int main(int argc, char** argv) {
test("127.0.0.1");
test("127.0.0.1:80");
test("::ffff:127.0.0.1");
test("::1");
test("[::1]:80");
test("1::80");
test("2605:2700:0:3::4713:93e3");
test("[2605:2700:0:3::4713:93e3]:80");
return 0;
}</syntaxhighlight>

{{out}}
<pre>
input: 127.0.0.1
address family: IPv4
address number: 7F000001
port not specified

input: 127.0.0.1:80
address family: IPv4
address number: 7F000001
port: 80

input: ::ffff:127.0.0.1
address family: IPv6
address number: 00000000000000000000FFFF7F000001
port not specified

input: ::1
address family: IPv6
address number: 00000000000000000000000000000001
port not specified

input: [::1]:80
address family: IPv6
address number: 00000000000000000000000000000001
port: 80

input: 1::80
address family: IPv6
address number: 00010000000000000000000000000080
port not specified

input: 2605:2700:0:3::4713:93e3
address family: IPv6
address number: 260527000000000300000000471393E3
port not specified

input: [2605:2700:0:3::4713:93e3]:80
address family: IPv6
address number: 260527000000000300000000471393E3
port: 80

</pre>

=={{header|F_Sharp|F#}}==
<syntaxhighlight lang="fsharp">
// Parse IP addresses: Nigel Galloway. May 29th., 2021
open System.Text.RegularExpressions
type ipv6= Complete |Composite |Compressed |CompressedComposite
let ip4n,ip6i,ip6g,ip6e,ip6l=let n,g="[0-9a-fA-F]{1,4}","(25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]?[0-9])" in (
sprintf "^(%s)\.(%s)\.(%s)\.(%s)$" g g g g, sprintf "^(%s):(%s):(%s):(%s):(%s):(%s):(%s):(%s)$" n n n n n n n n,
sprintf "^((%s):)?((%s):)?((%s):)?((%s):)?((%s):)?((%s):)?(^|%s)::(%s|$)(:(%s))?(:(%s))?(:(%s))?(:(%s))?(:(%s))?(:(%s))?$" n n n n n n n n n n n n n n,
sprintf "^(%s):(%s):(%s):(%s):(%s):(%s):(%s)\.(%s)\.(%s)\.(%s)$" n n n n n n g g g g,
sprintf "^((%s):)?((%s):)?((%s):)?((%s):)?(^|%s)::((%s):)?((%s):)?((%s):)?((%s):)?((%s):)?(%s)\.(%s)\.(%s)\.(%s)$" n n n n n n n n n n g g g g)
let mn,mi,mg,me,ml=[2;4;6;8;10;12;13], [14..2..26], [2;4;6;8;9], [11..2..19], [20..5..35]
let fN(n:Match) g=g|>List.filter(fun(g:int)->n.Groups.[g].Length>0)
let fI n (g:Match)=n|>List.fold(fun Σ (n:int)->(Σ<<<16)+((int>>bigint)(sprintf "0x%s" g.Groups.[n].Value)))0I
let rec fG n g=let a="0123456789abcdef" in match bigint.DivRem(n,16I) with (n,r) when n=0I->a.[int r]::g|>Array.ofList|>System.String |(n,r)->fG n (a.[int r]::g)
let fE(m:Match) n g=(fN m n,fN m g)
let fL n (g:Match)=n|>List.fold(fun Σ (n:int)->(Σ<<<8)+int(g.Groups.[n].Value))0
let (|IP4 |_|) n=let g=Regex.Match(n,ip4n) in if g.Success then Some(fL [1..5..16] g) else None
let (|IP6n|_|) i=let g=Regex.Match(i,ip6i) in if g.Success then Some(fI [1..8] g) else None
let (|IP6i|_|) g=let g=Regex.Match(g,ip6g) in if g.Success then let n,l=fE g mn mi in (if n.Length+l.Length<8 then Some(((fI n g)<<<((8-n.Length)*16))+(fI l g)) else None) else None
let (|IP6g|_|) e=let g=Regex.Match(e,ip6e) in if g.Success then Some(((fI [1..6] g)<<<32)+bigint(fL [7..5..22] g)) else None
let (|IP6e|_|) l=let g=Regex.Match(l,ip6l) in if g.Success then let n,l=fE g mg me in (if n.Length+l.Length<6 then Some(((fI n g)<<<((8-n.Length)*16))+((fI l g)<<<32)+bigint(fL ml g)) else None) else None
let (|IP6l|_|) n=match n with IP6n n->Some(Complete,fG n []) |IP6i n->Some(Compressed,fG n []) |IP6g n->Some(Composite,fG n []) |IP6e n->Some(CompressedComposite,fG n []) |_->None
let (|IP4p|_|) n=let g=Regex.Match(n,"^(.+):(\d{1,4})$") in if g.Success then match g.Groups.[1].Value with IP4 n->Some(n,int g.Groups.[2].Value) |_->None else None
let (|IP6p|_|) n=let g=Regex.Match(n,"^\[(.+)\]:(\d{1,4})$") in if g.Success then match g.Groups.[1].Value with IP6l n->Some(n,int g.Groups.[2].Value) |_->None else None
let pIP n=match n with IP6p((t,g),p)->printfn "%s is a %A IPv6 address value 0x%s using port %d" n t g p
|IP4 g->printfn "%s is an IPv4 address value %0x" n g
|IP6l(t,g)->printfn "%s is a %A IPv6 address value 0x%s" n t g
|IP4p(g,p)->printfn "%s is an IPv4 address value %0x using port %d" n g p
|_->printfn "%s not matched" n

["127.0.0.1";"127.0.0.1:80";"2605:2700:0:3::4713:93e3";"::1";"[::1]:80";"2605:2700:0:3::4713:93e3";"[2605:2700:0:3::4713:93e3]:80";
"::ffff:127.0.0.1";"1:2:3:4:5:6:7:8";"1:2:3:4:5:6:7:8:9";"1:2:3:4:5:6:127.0.0.1"]|>List.iter pIP
</syntaxhighlight>
{{out}}
<pre>
127.0.0.1 is an IPv4 address value 7f000001
127.0.0.1:80 is an IPv4 address value 7f000001 using port 80
2605:2700:0:3::4713:93e3 is a Compressed IPv6 address value 0x260527000000000300000000471393e3
::1 is a Compressed IPv6 address value 0x1
[::1]:80 is a Compressed IPv6 address value 0x1 using port 80
2605:2700:0:3::4713:93e3 is a Compressed IPv6 address value 0x260527000000000300000000471393e3
[2605:2700:0:3::4713:93e3]:80 is a Compressed IPv6 address value 0x260527000000000300000000471393e3 using port 80
::ffff:127.0.0.1 is a CompressedComposite IPv6 address value 0xffff7f000001
1:2:3:4:5:6:7:8 is a Complete IPv6 address value 0x10002000300040005000600070008
1:2:3:4:5:6:7:8:9 not matched
1:2:3:4:5:6:127.0.0.1 is a Composite IPv6 address value 0x1000200030004000500067f000001
</pre>
=={{header|Go}}==
=={{header|Go}}==
<lang go>package main
<syntaxhighlight lang="go">package main


import (
import (
"encoding/hex"
"errors"
"fmt"
"fmt"
"io"
"net"
"net"
"os"
"strconv"
"strconv"
"strings"
"strings"
"text/tabwriter"
)
)


// parseIPPort parses an IP with an optional port, returning an IP and a port (or nil
func ParseIPPort(s string) (ip net.IP, port, space string, err error) {
// if no port was present in the given address).
ip = net.ParseIP(s)
func parseIPPort(address string) (net.IP, *uint64, error) {
if ip == nil {
ip := net.ParseIP(address)
var host string
if ip != nil {
host, port, err = net.SplitHostPort(s)
if err != nil {
return ip, nil, nil
return
}
if port != "" {
// This check only makes sense if service names are not allowed
if _, err = strconv.ParseUint(port, 10, 16); err != nil {
return
}
}
ip = net.ParseIP(host)
}
}

host, portStr, err := net.SplitHostPort(address)
if err != nil {
return nil, nil, fmt.Errorf("splithostport failed: %w", err)
}

port, err := strconv.ParseUint(portStr, 10, 16)
if err != nil {
return nil, nil, fmt.Errorf("failed to parse port: %w", err)
}

ip = net.ParseIP(host)
if ip == nil {
if ip == nil {
return nil, nil, fmt.Errorf("failed to parse ip address")
err = errors.New("invalid address format")
} else {
space = "IPv6"
if ip4 := ip.To4(); ip4 != nil {
space = "IPv4"
ip = ip4
}
}
}

return
return ip, &port, nil
}

func ipVersion(ip net.IP) int {
if ip.To4() == nil {
return 6
}

return 4
}
}


func main() {
func main() {
var testCases = []string{
testCases := []string{
"127.0.0.1",
"127.0.0.1",
"127.0.0.1:80",
"127.0.0.1:80",
"::1",
"::1",
"[::1]:80",
"[::1]:443",
"2605:2700:0:3::4713:93e3",
"2605:2700:0:3::4713:93e3",
"[2605:2700:0:3::4713:93e3]:80",
"[2605:2700:0:3::4713:93e3]:80",
}
}

max := len("Input")
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
for _, addr := range testCases {

if len(addr) > max {
writeTSV := func(w io.Writer, args ...interface{}) {
max = len(addr)
fmt.Fprintf(w, strings.Repeat("%s\t", len(args)), args...)
}
fmt.Fprintf(w, "\n")
}
}

fmt.Printf("%-*s %*s %-6s %s\n", max, "Input",
2*net.IPv6len, "Address", "Space", "Port")
writeTSV(w, "Input", "Address", "Space", "Port")

for _, addr := range testCases {
for _, addr := range testCases {
fmt.Printf("%-*s ", max, addr)
ip, port, err := parseIPPort(addr)
ip, port, space, err := ParseIPPort(addr)
if err != nil {
if err != nil {
fmt.Println(err)
panic(err)
continue
}
}

fmt.Print(strings.Repeat(" ", net.IPv6len-len(ip)))
for _, b := range ip {
portStr := "n/a"
if port != nil {
fmt.Printf("%02x", b)
portStr = fmt.Sprint(*port)
}
}

fmt.Printf(" %-6s %s\n", space, port)
ipVersion := fmt.Sprintf("IPv%d", ipVersion(ip))

writeTSV(w, addr, hex.EncodeToString(ip), ipVersion, portStr)
}
}

}</lang>
w.Flush()
}
</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Input Address Space Port
Input Address Space Port
127.0.0.1 7f000001 IPv4
127.0.0.1 00000000000000000000ffff7f000001 IPv4
127.0.0.1:80 7f000001 IPv4 80
127.0.0.1:80 00000000000000000000ffff7f000001 IPv4 80
::1 00000000000000000000000000000001 IPv6
::1 00000000000000000000000000000001 IPv6
[::1]:80 00000000000000000000000000000001 IPv6 80
[::1]:443 00000000000000000000000000000001 IPv6 443
2605:2700:0:3::4713:93e3 260527000000000300000000471393e3 IPv6
2605:2700:0:3::4713:93e3 260527000000000300000000471393e3 IPv6
[2605:2700:0:3::4713:93e3]:80 260527000000000300000000471393e3 IPv6 80
[2605:2700:0:3::4713:93e3]:80 260527000000000300000000471393e3 IPv6 80
</pre>
</pre>


=={{header|Haskell}}==
=={{header|Haskell}}==
<lang Haskell>import Data.List (isInfixOf)
<syntaxhighlight lang="haskell">import Data.List (isInfixOf)
import Numeric (showHex)
import Numeric (showHex)
import Data.Char (isDigit)
import Data.Char (isDigit)
Line 660: Line 1,269:
"2605:2700:0:3::4713:93e3", -- Rosetta Code
"2605:2700:0:3::4713:93e3", -- Rosetta Code
"[2605:2700:0:3::4713:93e3]:80"] -- Rosetta Code
"[2605:2700:0:3::4713:93e3]:80"] -- Rosetta Code
</syntaxhighlight>
</lang>
Output:<pre>
Output:<pre>
IPv4 7f000001
IPv4 7f000001
Line 671: Line 1,280:


=={{header|Icon}} and {{header|Unicon}}==
=={{header|Icon}} and {{header|Unicon}}==
<lang Icon>link printf, hexcvt
<syntaxhighlight lang="icon">link printf, hexcvt


procedure main()
procedure main()
Line 683: Line 1,292:
"::", # unspecified
"::", # unspecified
"::ffff:192.168.0.1", # transition
"::ffff:192.168.0.1", # transition
"2605:2700:0:3::4713:93e3", # RC
"2605:2700:0:3::4713:93e3", # RC
"[2605:2700:0:3::4713:93e3]:80", # RC
"[2605:2700:0:3::4713:93e3]:80", # RC
"::ffff:71.19.147.227", # RC transition
"::ffff:71.19.147.227", # RC transition
Line 751: Line 1,360:
}
}
}
}
end</lang>
end</syntaxhighlight>


{{libheader|Icon Programming Library}}
{{libheader|Icon Programming Library}}
Line 778: Line 1,387:
Implementation:
Implementation:


<lang J>parseaddr=:3 :0
<syntaxhighlight lang="j">parseaddr=:3 :0
if. '.' e. y do.
if. '.' e. y do.
if. +./'::' E. y do.
if. +./'::' E. y do.
Line 814: Line 1,423:
((#y){.'v';'addr';'port')=. y
((#y){.'v';'addr';'port')=. y
'ipv',(":v),' ',(hfd addr),(#port)#' ',":port
'ipv',(":v),' ',(hfd addr),(#port)#' ',":port
)</lang>
)</syntaxhighlight>


Task examples:
Task examples:


<lang J> fmt parseaddr '127.0.0.1'
<syntaxhighlight lang="j"> fmt parseaddr '127.0.0.1'
ipv4 7f000001
ipv4 7f000001
fmt parseaddr '127.0.0.1:80'
fmt parseaddr '127.0.0.1:80'
Line 829: Line 1,438:
ipv6 260527000000000300000000471393e3
ipv6 260527000000000300000000471393e3
fmt parseaddr '[2605:2700:0:3::4713:93e3]:80'
fmt parseaddr '[2605:2700:0:3::4713:93e3]:80'
ipv6 260527000000000300000000471393e3 80</lang>
ipv6 260527000000000300000000471393e3 80</syntaxhighlight>


The intermediate (unformatted) result from parseaddr is the protocol number (4 or 6), the address and optionally the port:<syntaxhighlight lang="j"> parseaddr '127.0.0.1'
4 2130706433
parseaddr '127.0.0.1:80'
4 2130706433 80
parseaddr '::1'
6 1
parseaddr '[::1]:80'
6 1 80
parseaddr '2605:2700:0:3::4713:93e3'
6 50537416338094019778974086937420469219
parseaddr '[2605:2700:0:3::4713:93e3]:80'
6 50537416338094019778974086937420469219 80</syntaxhighlight>


=={{header|Java}}==
=={{header|Java}}==
<syntaxhighlight lang="java">
{{works with|Java|7}}
import java.util.regex.Matcher;
Implementation:

<lang Java>import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Pattern;
import java.util.regex.Pattern;


public class ParseIPAddress {
import javax.xml.bind.DatatypeConverter;


public static void main(String[] args) {
/**
String [] tests = new String[] {"192.168.0.1", "127.0.0.1", "256.0.0.1", "127.0.0.1:80", "::1", "[::1]:80", "[32e::12f]:80", "2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80", "2001:db8:85a3:0:0:8a2e:370:7334"};
* Parses ipv4 and ipv6 addresses. Emits each described IP address as a
System.out.printf("%-40s %-32s %s%n", "Test Case", "Hex Address", "Port");
* hexadecimal integer representing the address, the address space, and the port
for ( String ip : tests ) {
* number specified, if any.
try {
*/
String [] parsed = parseIP(ip);
public class IPParser {
System.out.printf("%-40s %-32s %s%n", ip, parsed[0], parsed[1]);
/*
}
* Using regex to ensure that the address is a valid one. This allows for
catch (IllegalArgumentException e) {
* separating by format and ensures that the operations done on a format
System.out.printf("%-40s Invalid address: %s%n", ip, e.getMessage());
* will be valid.
}
*/
}
// 0.0.0.0-255.255.255.255
}
private final String ipv4segment =
"(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])";
private static final Pattern IPV4_PAT = Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)(?::(\\d+)){0,1}$");
private static final Pattern IPV6_DOUBL_COL_PAT = Pattern.compile("^\\[{0,1}([0-9a-f:]*)::([0-9a-f:]*)(?:\\]:(\\d+)){0,1}$");
private static String ipv6Pattern;
static {
ipv6Pattern = "^\\[{0,1}";
for ( int i = 1 ; i <= 7 ; i ++ ) {
ipv6Pattern += "([0-9a-f]+):";
}
ipv6Pattern += "([0-9a-f]+)(?:\\]:(\\d+)){0,1}$";
}
private static final Pattern IPV6_PAT = Pattern.compile(ipv6Pattern);
private static String[] parseIP(String ip) {
String hex = "";
String port = "";
// IPV4
Matcher ipv4Matcher = IPV4_PAT.matcher(ip);
if ( ipv4Matcher.matches() ) {
for ( int i = 1 ; i <= 4 ; i++ ) {
hex += toHex4(ipv4Matcher.group(i));
}
if ( ipv4Matcher.group(5) != null ) {
port = ipv4Matcher.group(5);
}
return new String[] {hex, port};
}
// IPV6, double colon
Matcher ipv6DoubleColonMatcher = IPV6_DOUBL_COL_PAT.matcher(ip);
if ( ipv6DoubleColonMatcher.matches() ) {
String p1 = ipv6DoubleColonMatcher.group(1);
if ( p1.isEmpty() ) {
p1 = "0";
}
String p2 = ipv6DoubleColonMatcher.group(2);
if ( p2.isEmpty() ) {
p2 = "0";
}
ip = p1 + getZero(8 - numCount(p1) - numCount(p2)) + p2;
if ( ipv6DoubleColonMatcher.group(3) != null ) {
ip = "[" + ip + "]:" + ipv6DoubleColonMatcher.group(3);
}
}
// IPV6
Matcher ipv6Matcher = IPV6_PAT.matcher(ip);
if ( ipv6Matcher.matches() ) {
for ( int i = 1 ; i <= 8 ; i++ ) {
hex += String.format("%4s", toHex6(ipv6Matcher.group(i))).replace(" ", "0");
}
if ( ipv6Matcher.group(9) != null ) {
port = ipv6Matcher.group(9);
}
return new String[] {hex, port};
}
throw new IllegalArgumentException("ERROR 103: Unknown address: " + ip);
}
private static int numCount(String s) {
return s.split(":").length;
}
private static String getZero(int count) {
StringBuilder sb = new StringBuilder();
sb.append(":");
while ( count > 0 ) {
sb.append("0:");
count--;
}
return sb.toString();
}


private static String toHex4(String s) {
// 0-65535
int val = Integer.parseInt(s);
private final String portsegment =
if ( val < 0 || val > 255 ) {
":(?:6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|"
throw new IllegalArgumentException("ERROR 101: Invalid value : " + s);
+ "6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{1,3}|[0-9])";
}
private final String ipv4address = "(" + ipv4segment + "\\.){3,3}"
return String.format("%2s", Integer.toHexString(val)).replace(" ", "0");
+ ipv4segment;
}
private final String ipv4addressWithPort = ipv4address + portsegment + "?";
private final String ipv6segment = "[a-fA-F0-9]{1,4}";
private final String ipv6address = "(" +
// 1:2:3:4:5:6:7:8
"(" + ipv6segment + ":){7,7}" + ipv6segment + "|" +
// 1::, 1:2:3:4:5:6:7::
"(" + ipv6segment + ":){1,7}:|" +
// 1::8, 1:2:3:4:5:6::8, 1:2:3:4:5:6::8
"(" + ipv6segment + ":){1,6}:" + ipv6segment + "|" +
// 1::7:8, 1:2:3:4:5::7:8, 1:2:3:4:5::8
"(" + ipv6segment + ":){1,5}(:" + ipv6segment + "){1,2}|" +
// 1::6:7:8, 1:2:3:4::6:7:8, 1:2:3:4::8
"(" + ipv6segment + ":){1,4}(:" + ipv6segment + "){1,3}|" +
// 1::5:6:7:8, 1:2:3::5:6:7:8, 1:2:3::8
"(" + ipv6segment + ":){1,3}(:" + ipv6segment + "){1,4}|" +
// # 1::4:5:6:7:8, 1:2::4:5:6:7:8, 1:2::8
"(" + ipv6segment + ":){1,2}(:" + ipv6segment + "){1,5}|" +
// # 1::3:4:5:6:7:8, 1::3:4:5:6:7:8, 1::8
ipv6segment + ":((:" + ipv6segment + "){1,6})|" +
// ::2:3:4:5:6:7:8, ::2:3:4:5:6:7:8, ::8, ::
":((:" + ipv6segment + "){1,7}|:)|" +
// fe80::7:8%eth0, fe80::7:8%1 (link-local IPv6 addresses with
// zone index)
"fe80:(:" + ipv6segment + "){0,4}%[0-9a-zA-Z]{1,}|" +
// ::255.255.255.255, ::ffff:255.255.255.255,
// ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and
// IPv4-translated addresses)
"::(ffff(:0{1,4}){0,1}:){0,1}" + ipv4address + "|" +
// 2001:db8:3:4::192.0.2.33, 64:ff9b::192.0.2.33 (IPv4-Embedded
// IPv6 Address)
"(" + ipv6segment + ":){1,4}:" + ipv4address + ")";


private static String toHex6(String s) {
private final String ipv6addressWithPort = "\\[" + ipv6address + "\\]"
int val = Integer.parseInt(s, 16);
+ portsegment + "?";
if ( val < 0 || val > 65536 ) {
throw new IllegalArgumentException("ERROR 102: Invalid hex value : " + s);
}
return s;
}


}
/**
</syntaxhighlight>
* Parses ipv4 and ipv6 addresses. Emits each described IP address as a
{{out}}
* hexadecimal integer representing the address, the address space, and the
<pre>
* port number specified, if any.
Test Case Hex Address Port
*
192.168.0.1 c0a80001
* @param address the address to analyze
127.0.0.1 7f000001
*/
256.0.0.1 Invalid address: ERROR 101: Invalid value : 256
public void parse(String address) {
127.0.0.1:80 7f000001 80
::1 00000000000000000000000000000001
[::1]:80 00000000000000000000000000000001 80
[32e::12f]:80 032e000000000000000000000000012f 80
2605:2700:0:3::4713:93e3 260527000000000300000000471393e3
[2605:2700:0:3::4713:93e3]:80 260527000000000300000000471393e3 80
2001:db8:85a3:0:0:8a2e:370:7334 20010db885a3000000008a2e03707334
</pre>


=={{header|jq}}==
// Used for storing values to be printed
'''Works with gojq''', the Go implementation of jq.
String space = "";// ipv4, ipv6, or unknown
String hex = "";// hex value of the address
String port = "";// the port or unknown


'''Adapted from [[#Wren|Wren]]'''
// Try to match the pattern with one of the 2 types, with or without a
// port
if (Pattern.matches("^" + ipv4address + "$", address)) {
InetAddress a;
space = "IPv4";
try {
a = InetAddress.getByName(address);
hex = DatatypeConverter.printHexBinary(a.getAddress());
}
catch (UnknownHostException e) {
e.printStackTrace();
hex = "Invalid";
}
port = "Absent";
}
else if (Pattern.matches("^" + ipv4addressWithPort + "$", address)) {
String[] parts = address.split("\\.");
port = parts[3].split(":")[1];
parts[3] = parts[3].split(":")[0];
InetAddress a;
space = "IPv4";
try {
address = parts[0] + parts[1] + parts[2] + parts[3];
a = InetAddress.getByName(address);
hex = DatatypeConverter.printHexBinary(a.getAddress());
}
catch (UnknownHostException e) {
e.printStackTrace();
hex = "Invalid";
}
}
else if (Pattern.matches("^" + ipv6address + "$", address)) {
InetAddress a;
space = "IPv6";
try {
a = Inet6Address.getByName(address);
hex = DatatypeConverter.printHexBinary(a.getAddress());
}
catch (UnknownHostException e) {
e.printStackTrace();
hex = "Invalid";
}
port = "Absent";
}
else if (Pattern.matches("^" + ipv6addressWithPort + "$", address)) {
String[] parts = address.split(":");
InetAddress a;
space = "IPv6";
address =
address.replace("[", "").replace("]", "")
.replaceAll(portsegment + "$", "");
try {
a = Inet6Address.getByName(address);
hex = DatatypeConverter.printHexBinary(a.getAddress());
}
catch (UnknownHostException e) {
e.printStackTrace();
hex = "Invalid";
}
port = parts[parts.length - 1];
}
else {
// Not a valid address
hex = "Invalid";
space = "Invalid";
port = "Invalid";
}


<syntaxhighlight lang="jq">
// Output the findings to the console
# Generic preliminaries
System.out.println("Test case: '" + address + "'");
System.out.println("Space: " + space);
System.out.println("Address: " + hex);
System.out.println("Port: " + port);
System.out.println();


# To take advantage of gojq's arbitrary-precision integer arithmetic:
}
def power($b): . as $in | reduce range(0;$b) as $i (1; . * $in);


# To take advantage of gojq's arbitrary-precision integer arithmetic:
/**
# if the input and $j are integers, then the result will be an integer.
* Tests the parser using various addresses.
def div($j):
*
(. - (. % j)) / $j;
* @param args arguments for the program
*/
public static void main(String[] args) {
IPParser parser = new IPParser();


# integer to stream of 0s and 1s, least significant bit first
// The "localhost" IPv4 address
def bitwise:
parser.parse("127.0.0.1");
recurse( if . >= 2 then div(2) else empty end) | . % 2;
// The "localhost" IPv4 address, with a specified port (80)
parser.parse("127.0.0.1:80");
// The "localhost" IPv6 address
parser.parse("::1");
// The "localhost" IPv6 address, with a specified port (80)
parser.parse("[::1]:80");
// Rosetta Code's primary server's public IPv6 address
parser.parse("2605:2700:0:3::4713:93e3");
// Rosetta Code's primary server's public IPv6 address, with a specified
// port (80)
parser.parse("[2605:2700:0:3::4713:93e3]:80");


# inverse of `bitwise`
// ipv6 space
def stream_to_integer(stream):
parser.parse("::ffff:192.168.173.22");
reduce stream as $c ( {power:1 , ans: 0};
// ipv6 space with port
.ans += ($c * .power) | .power *= 2 )
parser.parse("[::ffff:192.168.173.22]:80");
| .ans;
// trailing compression
parser.parse("1::");
// trailing compression with port
parser.parse("[1::]:80");
// 'any' address compression
parser.parse("::");
// 'any' address compression with port
parser.parse("[::]:80");
}
}
</lang>
output<lang>
Test case: '127.0.0.1'
Space: IPv4
Address: 7F000001
Port: Absent


# Input determines the max number of bits to be retained
Test case: '127.0.0.1:80'
# $x and $y are two integers
Space: IPv4
def xorBits($x;$y):
Address: 0001F019
def lxor(a;b):
Port: 80
if (a==1 or b==1) and ((a==1 and b==1)|not) then 1
elif a == null then b
elif b == null then a
else 0
end;
if $x == 0 then $y
elif $y == 0 then $x
else
[if . then limit(.; $x|bitwise) else $x|bitwise end] as $s
| [if . then limit(.; $y|bitwise) else $y|bitwise end] as $t
| stream_to_integer(
range(0; [($s|length), ($t|length)] | max) as $i
| lxor($s[$i]; $t[$i]) )
end ;


# $x and $y are two integers
Test case: '::1'
def xor($x;$y):
Space: IPv6
null | xorBits($x;$y);
Address: 00000000000000000000000000000001
Port: Absent


def count(stream): reduce stream as $i (0; .+1);
Test case: '[::1]:80'
Space: IPv6
Address: 00000000000000000000000000000001
Port: 80


# Input: an array
Test case: '2605:2700:0:3::4713:93e3'
def insert($i; $x): .[:$i] + [$x] + .[$i:];
Space: IPv6
Address: 260527000000000300000000471393E3
Port: Absent


# Input: a non-negative integer
Test case: '[2605:2700:0:3::4713:93e3]:80'
def tobase($b):
Space: IPv6
def digit: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[.:.+1];
Address: 260527000000000300000000471393E3
Port: 80
def mod: . % $b;
def div: ((. - mod) / $b);
def digits: recurse( select(. > 0) | div) | mod ;
# For jq it would be wise to protect against `infinite` as input, but using `isinfinite` confuses gojq
select( (tostring|test("^[0-9]+$")) and 2 <= $b and $b <= 36)
| if . == 0 then "0"
else [digits | digit] | reverse[1:] | add
end;


# Input: a string in base $b
Test case: '::ffff:192.168.173.22'
# Output: its decimal value
Space: IPv6
def frombase($b):
Address: C0A8AD16
def decimalValue:
Port: Absent
if 48 <= . and . <= 57 then . - 48
elif 65 <= . and . <= 90 then . - 55 # (10+.-65)
elif 97 <= . and . <= 122 then . - 87 # (10+.-97)
else "decimalValue <- \(.)" | error
end;
reduce (explode|reverse[]|decimalValue) as $x ({p:1};
.value += (.p * $x)
| .p *= $b)
| .value ;


### Parse an IP address
Test case: '[::ffff:192.168.173.22]:80'
Space: IPv6
Address: C0A8AD16
Port: 80


# An IPAddress is represented by an object {"address", "addressSpace", "port"}
Test case: '1::'
# where addressSpace is one of "IPv4", "IPv6", "Invalid"
Space: IPv6
# and a port of -1 denotes 'not specified'.
Address: 00010000000000000000000000000000
Port: Absent


def INVALID: {address: 0, addressSpace: "Invalid", port: 0};
Test case: '[1::]:80'
Space: IPv6
Address: 00010000000000000000000000000000
Port: 80


def ipAddressParse:
Test case: '::'
Space: IPv6
Address: 00000000000000000000000000000000
Port: Absent


# Helper for octet1
Test case: '[::]:80'
# Assumes .len == (.hextets|length)
Space: IPv6
def fixhextets:
Address: 00000000000000000000000000000000
.insertions = (8 - .len)
Port: 80
| .i = 0
</lang>
| until(.i == 8;
if .hextets[.i] == ""
then .hextets[.i] = "0"
| until( .insertions <= 0;
.insertions += -1
| .i as $i
| .hextets |= insert($i; "0") )
| .i = 8
else .i += 1
end ) ;
# Handle the case when octet length is 4
def octet4:
(.octets[0] | split(":")) as $split
| if $split|length == 2
then ($split[1]|tonumber? // null) as $temp
| if $temp | (. == null or . < 0 or . > 65535)
then .return = INVALID
else .port = $temp
| .octets[0] = $split[0]
end
else .
end
| if .return then .
else reduce range(0;4) as $i (.;
if .return then .
else (.octets[$i] | tonumber? // null) as $num
| if $num | (. == null or . < 0 or . > 255) then .return = INVALID
else .address = xor(.address; $num * (2 | power($i * 8)))
end
end)
end
| if .return then .
elif .trans
then .address += 281470681743360 # "ffff00000000"
else .
end ;


# Handle the case when octet length is 1
def octet1:
.addressSpace = "IPv6"
| if .ipa[0:1] == "["
then .ipa |= .[1:]
| (.ipa | split("]:")) as $split
| if $split|length != 2 then .return = INVALID
else ($split[1] | tonumber? // null) as $temp
| if $temp | (. == null or . < 0 or . > 65535) then .return = INVALID
else .port = $temp
| .ipa |= .[0: (-2 - ($split[1]|length))]
end
end
else .
end
| if .return then .
else .hextets = (.ipa | split(":")|reverse)
| .len = (.hextets|length)
| if .ipa|startswith("::")
then .hextets[-1] = "0"
elif .ipa|endswith("::")
then .hextets[0] = "0"
else .
end
| if .ipa == "::" then .hextets[1] = "0" else . end
| if .len > 8 or (.len == 8 and any(.hextets[]; . == "")) or count(.hextets[] | select(. == "")) > 1
then .return = INVALID
else .
end
end
| if .return then .
elif .len < 8
then fixhextets
else .
end
| if .return then .
else reduce range(0; 8) as $j (.;
if .return then .
else (.hextets[$j] | frombase(16)) as $num
| if $num > 65535 then .return = INVALID
else .address = xor(.address; $num * (2 | power($j * 16)))
end
end)
end ;


{ addressSpace: "IPv4",
=={{header|Perl}}==
ipa: ascii_downcase,
<lang perl>sub parse_v4 {
port: -1,
my ($ip, $port) = @_;
trans: false }
my @quad = split(/\./, $ip);
| if (.ipa|startswith("::ffff:")) and (.ipa|test("[.]"))
then .addressSpace = "IPv6"
| .trans = true
| .ipa |= .[7:]
elif (.ipa|startswith("[::ffff:")) and (.ipa|test("[.]"))
then .addressSpace = "IPv6"
| .trans = true
| .ipa |= (.[8:] | gsub("]";""))
else .
end
| .octets = (.ipa | split(".") | reverse)
| .address = 0
| if .octets|length == 4
then octet4
elif .octets|length == 1
then octet1
else .return = INVALID
end
| if .return then .return
else {address, addressSpace, port}
end ;


# Examples
return unless @quad == 4;
def ipas:
for (@quad) { return if ($_ > 255) }
"127.0.0.1",
"127.0.0.1:80",
"::1",
"[::1]:80",
"2605:2700:0:3::4713:93e3",
"[2605:2700:0:3::4713:93e3]:80",
"::ffff:192.168.173.22",
"[::ffff:192.168.173.22]:80",
"1::",
"::",
"256.0.0.0",
"::ffff:127.0.0.0.1"
;


ipas
if (!length $port) { $port = -1 }
| "IP address : \(.)",
elsif ($port =~ /^(\d+)$/) { $port = $1 }
( ipAddressParse
else { return }
| "Address : \(.address|tobase(16))",
"Address Space : \(.addressSpace)",
"Port : \(if .port == -1 then "not specified" else .port end)",
""
)
</syntaxhighlight>
'''Invocation''': gojq -nr -f parse-an-ip-address.jq
{{output}}
Exactly as for [[#Wren|Wren]]


my $h = join '' => map(sprintf("%02x", $_), @quad);
return $h, $port
}


=={{header|Julia}}==
sub parse_v6 {
<syntaxhighlight lang="julia">
my $ip = shift;
const testdata = ["127.0.0.1", "127.0.0.1:80", "::1", "[::1]:80",
my $omits;
"2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80",
"::ffff:192.168.173.22", "[::ffff:192.168.173.22]:80",
"1::", "[1::]:80", "::", "[::]:80"]


maybev4(ip) = search(ip, '.') > 0 && length(matchall(r":", ip)) < 2
return unless $ip =~ /^[\da-f:.]+$/i; # invalid char
maybev6(ip) = length(matchall(r":", ip)) > 1


function parseip(ip)
$ip =~ s/^:/0:/;
if (mat = match(r"^\[([:.\da-fA-F]+)\]:(\d+)$", ip))!= nothing ||
$omits = 1 if $ip =~ s/::/:z:/g;
(mat = match(r"^([\d.]+)[:/](\d+)$", ip)) != nothing
return if $ip =~ /z.*z/; # multiple omits illegal
port = mat.captures[2]
ip = mat.captures[1]
else
port = "none"
end
if maybev4(ip)
println("Processing ip v4 $ip")
iphex = hex(Int(Base.IPv4(ip)))
addresspace = "IPv4"
elseif maybev6(ip)
println("Processing ip v6 $ip")
iphex = hex(UInt128(Base.IPv6(ip)))
addresspace = "IPv6"
else
throw("Bad IP address argument $ip")
end
iphex, addresspace, port
end


for ip in testdata
my $v4 = '';
hx, add, por = parseip(ip)
my $len = 8;
println("For input $ip, IP in hex is $hx, address space $add, port $por.")
end
</syntaxhighlight>
{{output}}
<pre>
Processing ip v4 127.0.0.1
For input 127.0.0.1, IP in hex is 7f000001, address space IPv4, port none.
Processing ip v4 127.0.0.1
For input 127.0.0.1:80, IP in hex is 7f000001, address space IPv4, port 80.
Processing ip v6 ::1
For input ::1, IP in hex is 1, address space IPv6, port none.
Processing ip v6 ::1
For input [::1]:80, IP in hex is 1, address space IPv6, port 80.
Processing ip v6 2605:2700:0:3::4713:93e3
For input 2605:2700:0:3::4713:93e3, IP in hex is 260527000000000300000000471393e3, address space IPv6, port none.
Processing ip v6 2605:2700:0:3::4713:93e3
For input [2605:2700:0:3::4713:93e3]:80, IP in hex is 260527000000000300000000471393e3, address space IPv6, port 80.
Processing ip v6 ::ffff:192.168.173.22
For input ::ffff:192.168.173.22, IP in hex is ffffc0a8ad16, address space IPv6, port none.
Processing ip v6 ::ffff:192.168.173.22
For input [::ffff:192.168.173.22]:80, IP in hex is ffffc0a8ad16, address space IPv6, port 80.
Processing ip v6 1::
For input 1::, IP in hex is 10000000000000000000000000000, address space IPv6, port none.
Processing ip v6 1::
For input [1::]:80, IP in hex is 10000000000000000000000000000, address space IPv6, port 80.
Processing ip v6 ::
For input ::, IP in hex is 0, address space IPv6, port none.
Processing ip v6 ::
For input [::]:80, IP in hex is 0, address space IPv6, port 80.
</pre>


=={{header|Kotlin}}==
if ($ip =~ s/:((?:\d+\.){3}\d+)$//) {
<syntaxhighlight lang="scala">// version 1.1.3
# hybrid 4/6 ip
($v4) = parse_v4($1) or return;
$len -= 2;


import java.math.BigInteger
}
# what's left should be v6 only
return unless $ip =~ /^[:a-fz\d]+$/i;


enum class AddressSpace { IPv4, IPv6, Invalid }
my @h = split(/:/, $ip);
return if @h + $omits > $len; # too many segments


data class IPAddressComponents(
@h = map( $_ eq 'z' ? (0) x ($len - @h + 1) : ($_), @h);
val address: BigInteger,
return join('' => map(sprintf("%04x", hex($_)), @h)).$v4;
val addressSpace: AddressSpace,
}
val port: Int // -1 denotes 'not specified'
)


val INVALID = IPAddressComponents(BigInteger.ZERO, AddressSpace.Invalid, 0)
sub parse_ip {
my $str = shift;
fun ipAddressParse(ipAddress: String): IPAddressComponents {
$str =~ s/^\s*//;
var addressSpace = AddressSpace.IPv4
$str =~ s/\s*$//;
var ipa = ipAddress.toLowerCase()
var port = -1
var trans = false
if (ipa.startsWith("::ffff:") && '.' in ipa) {
addressSpace = AddressSpace.IPv6
trans = true
ipa = ipa.drop(7)
}
else if (ipa.startsWith("[::ffff:") && '.' in ipa) {
addressSpace = AddressSpace.IPv6
trans = true
ipa = ipa.drop(8).replace("]", "")
}
val octets = ipa.split('.').reversed().toTypedArray()
var address = BigInteger.ZERO
if (octets.size == 4) {
val split = octets[0].split(':')
if (split.size == 2) {
val temp = split[1].toIntOrNull()
if (temp == null || temp !in 0..65535) return INVALID
port = temp
octets[0] = split[0]
}
for (i in 0..3) {
val num = octets[i].toLongOrNull()
if (num == null || num !in 0..255) return INVALID
val bigNum = BigInteger.valueOf(num)
address = address.or(bigNum.shiftLeft(i * 8))
}


if (trans) address += BigInteger("ffff00000000", 16)
if ($str =~ s/^((?:\d+\.)+\d+)(?::(\d+))?$//) {
}
return 'v4', parse_v4($1, $2);
else if (octets.size == 1) {
}
addressSpace = AddressSpace.IPv6
if (ipa[0] == '[') {
ipa = ipa.drop(1)
val split = ipa.split("]:")
if (split.size != 2) return INVALID
val temp = split[1].toIntOrNull()
if (temp == null || temp !in 0..65535) return INVALID
port = temp
ipa = ipa.dropLast(2 + split[1].length)
}
val hextets = ipa.split(':').reversed().toMutableList()
val len = hextets.size


if (ipa.startsWith("::"))
my ($ip, $port);
hextets[len - 1] = "0"
if ($str =~ /^\[(.*?)\]:(\d+)$/) {
else if (ipa.endsWith("::"))
$port = $2;
hextets[0] = "0"
$ip = parse_v6($1);
} else {
$port = -1;
$ip = parse_v6($str);
}


if (ipa == "::") hextets[1] = "0"
return unless $ip;
if (len > 8 || (len == 8 && hextets.any { it == "" }) || hextets.count { it == "" } > 1)
return 'v6', $ip, $port;
return INVALID
if (len < 8) {
var insertions = 8 - len
for (i in 0..7) {
if (hextets[i] == "") {
hextets[i] = "0"
while (insertions-- > 0) hextets.add(i, "0")
break
}
}
}
for (j in 0..7) {
val num = hextets[j].toLongOrNull(16)
if (num == null || num !in 0x0..0xFFFF) return INVALID
val bigNum = BigInteger.valueOf(num)
address = address.or(bigNum.shiftLeft(j * 16))
}
}
else return INVALID

return IPAddressComponents(address, addressSpace, port)
}
}


fun main(args: Array<String>) {
for (qw/127.0.0.1 127.0.0.1:80
val ipas = listOf(
::1
"127.0.0.1",
[::1]:80
"127.0.0.1:80",
2605:2700:0:3::4713:93e3
"::1",
[2605:2700:0:3::4713:93e3]:80
"[::1]:80",
::ffff:192.168.0.1
"2605:2700:0:3::4713:93e3",
[::ffff:192.168.0.1]:22
"[2605:2700:0:3::4713:93e3]:80",
::ffff:127.0.0.0.1
"::ffff:192.168.173.22",
a::b::1/)
"[::ffff:192.168.173.22]:80",
{
"1::",
print "$_\n\t";
"::",
my ($ver, $ip, $port) = parse_ip($_)
"256.0.0.0",
or print "parse error\n" and next;
"::ffff:127.0.0.0.1"
)
for (ipa in ipas) {
val (address, addressSpace, port) = ipAddressParse(ipa)
println("IP address : $ipa")
println("Address : ${"%X".format(address)}")
println("Address Space : $addressSpace")
println("Port : ${if (port == -1) "not specified" else port.toString()}")
println()
}
}</syntaxhighlight>


{{out}}
print "$ver $ip\tport $port\n\n";
<pre>
}</lang>output<lang>127.0.0.1
IP address : 127.0.0.1
v4 7f000001 port -1
Address : 7F000001
Address Space : IPv4
Port : not specified


127.0.0.1:80
IP address : 127.0.0.1:80
v4 7f000001 port 80
Address : 7F000001
Address Space : IPv4
Port : 80


IP address : ::1
::1
Address : 1
v6 00000000000000000000000000000001 port -1
Address Space : IPv6
Port : not specified


[::1]:80
IP address : [::1]:80
Address : 1
v6 00000000000000000000000000000001 port 80
Address Space : IPv6
Port : 80


2605:2700:0:3::4713:93e3
IP address : 2605:2700:0:3::4713:93e3
Address : 260527000000000300000000471393E3
v6 260527000000000300000000471393e3 port -1
Address Space : IPv6
Port : not specified


[2605:2700:0:3::4713:93e3]:80
IP address : [2605:2700:0:3::4713:93e3]:80
Address : 260527000000000300000000471393E3
v6 260527000000000300000000471393e3 port 80
Address Space : IPv6
Port : 80


::ffff:192.168.0.1
IP address : ::ffff:192.168.173.22
Address : FFFFC0A8AD16
v6 00000000000000000000ffffc0a80001 port -1
Address Space : IPv6
Port : not specified


[::ffff:192.168.0.1]:22
IP address : [::ffff:192.168.173.22]:80
Address : FFFFC0A8AD16
v6 00000000000000000000ffffc0a80001 port 22
Address Space : IPv6
Port : 80


IP address : 1::
::ffff:127.0.0.0.1
Address : 10000000000000000000000000000
parse error
Address Space : IPv6
a::b::1
parse error</lang>
Port : not specified


IP address : ::
=={{header|Perl 6}}==
Address : 0
<lang perl6>grammar IP_Addr {
Address Space : IPv6
token TOP { ^ [ <IPv4> | <IPv6> ] $ }
Port : not specified


IP address : 256.0.0.0
token IPv4 {
Address : 0
[ <d8> +% '.' ] <?{ $<d8> == 4 }> <port>?
Address Space : Invalid
{ @*by8 = @$<d8> }
}
Port : 0


IP address : ::ffff:127.0.0.0.1
token IPv6 {
| <ipv6>
Address : 0
Address Space : Invalid
| '[' <ipv6> ']' <port>
}
Port : 0
</pre>


=={{header|Nim}}==
token ipv6 {
<syntaxhighlight lang="nim">import net, sequtils, strscans, strutils
| <h16> +% ':' <?{ $<h16> == 8 }>
{ @*by16 = @$<h16> }


const NoPort = -1
| [ (<h16>) +% ':']? '::' (<h16>) +% ':' <?{ @$0 + @$1 <= 8 }>
{ @*by16 = @$0, '0' xx 8 - (@$0 + @$1), @$1 }


func parseIpAddressAndPort(str: string): tuple[ipAddr: IpAddress; port: int] =
| '::ffff:' <IPv4>
var ipString: string
{ @*by16 = '0' xx 5, 'ffff', by8to16 @*by8 }
}
var port: int
if str.scanf("[$+]:$i", ipString, port):
# IP v6 address with port.
return (ipString.parseIpAddress(), port)
if '.' in str and str.scanf("$+:$i", ipString, port):
# IP v4 address with port.
return (ipString.parseIpAddress(), port)
# IP address without port.
result = (str.parseIpAddress(), NoPort)


token d8 { (\d+) <?{ $0 < 256 }> }
token d16 { (\d+) <?{ $0 < 65536 }> }
token h16 { (<:hexdigit>+) <?{ @$0 <= 4 }> }


const Inputs = ["127.0.0.1", "127.0.0.1:80",
token port {
':' <d16> { $*port = +$<d16> }
"::1", "[::1]:80",
"2605:2700:0:3::4713:93e3",
}
"[2605:2700:0:3::4713:93e3]:80"]
}


# Room to reserve to display the input.
sub by8to16 (@m) { gather for @m -> $a,$b { take ($a * 256 + $b).fmt("%04x") } }
const InputSize = Inputs.mapIt(it.len).foldl(max(a, b)) + 2


echo "Input".alignLeft(InputSize), "Address".align(32), " Space", " Port"
my @cases = <
127.0.0.1
127.0.0.1:80
::1
[::1]:80
2605:2700:0:3::4713:93e3
[2605:2700:0:3::4713:93e3]:80
2001:db8:85a3:0:0:8a2e:370:7334
2001:db8:85a3::8a2e:370:7334
[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443
192.168.0.1
::ffff:192.168.0.1
::ffff:71.19.147.227
[::ffff:71.19.147.227]:80
::
256.0.0.0
g::1
0000
0000:0000
0000:0000:0000:0000:0000:0000:0000:0000
0000:0000:0000::0000:0000
0000::0000::0000:0000
ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff
fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
fff:ffff:0:ffff:ffff:ffff:ffff:ffff
>;


for @cases -> $addr {
for input in Inputs:
try:
my @*by8;
let (ipAddress, port) = input.parseIpAddressAndPort()
my @*by16;
let portStr = if port == NoPort: "" else: $port
my $*port;
case ipAddress.family
of IPv6:
echo input.alignLeft(InputSize),
ipAddress.address_v6.map(toHex).join().align(32),
"IP v6".align(7),
portStr.align(6)
of IPv4:
echo input.alignLeft(InputSize),
ipAddress.address_v4.map(toHex).join().align(32),
"IP v4".align(7),
portStr.align(6)


except ValueError:
IP_Addr.parse($addr);
echo "Invalid IP address: ", input</syntaxhighlight>


say $addr;
if @*by16 {
say " IPv6: ", @*by16».map({:16(~$_)})».fmt("%04x").join;
say " Port: ", $*port if $*port;
}
elsif @*by8 {
say " IPv4: ", @*by8».fmt("%02x").join;
say " Port: ", $*port if $*port;
}
else {
say " BOGUS!";
}
say '';
}</lang>
{{out}}
{{out}}
<pre>Input Address Space Port
<pre>127.0.0.1
127.0.0.1 7F000001 IP v4
IPv4: 7f000001
127.0.0.1:80 7F000001 IP v4 80
::1 00000000000000000000000000000001 IP v6
[::1]:80 00000000000000000000000000000001 IP v6 80
2605:2700:0:3::4713:93e3 260527000000000300000000471393E3 IP v6
[2605:2700:0:3::4713:93e3]:80 260527000000000300000000471393E3 IP v6 80</pre>


=={{header|Perl}}==
127.0.0.1:80
<syntaxhighlight lang="perl">sub parse_v4 {
IPv4: 7f000001
my ($ip, $port) = @_;
Port: 80
my @quad = split(/\./, $ip);


return unless @quad == 4;
::1
for (@quad) { return if ($_ > 255) }
IPv6: 00000000000000000000000000000001


if (!length $port) { $port = -1 }
[::1]:80
elsif ($port =~ /^(\d+)$/) { $port = $1 }
IPv6: 00000000000000000000000000000001
else { return }
Port: 80


my $h = join '' => map(sprintf("%02x", $_), @quad);
2605:2700:0:3::4713:93e3
return $h, $port
IPv6: 260527000000000300000000471393e3
}


sub parse_v6 {
[2605:2700:0:3::4713:93e3]:80
my $ip = shift;
IPv6: 260527000000000300000000471393e3
my $omits;
Port: 80


return unless $ip =~ /^[\da-f:.]+$/i; # invalid char
2001:db8:85a3:0:0:8a2e:370:7334
IPv6: 20010db885a3000000008a2e03707334


$ip =~ s/^:/0:/;
2001:db8:85a3::8a2e:370:7334
$omits = 1 if $ip =~ s/::/:z:/g;
IPv6: 20010db885a3000000008a2e03707334
return if $ip =~ /z.*z/; # multiple omits illegal


my $v4 = '';
[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443
my $len = 8;
IPv6: 20010db885a308d313198a2e03707348
Port: 443


if ($ip =~ s/:((?:\d+\.){3}\d+)$//) {
192.168.0.1
# hybrid 4/6 ip
IPv4: c0a80001
($v4) = parse_v4($1) or return;
$len -= 2;


}
::ffff:192.168.0.1
# what's left should be v6 only
IPv6: 00000000000000000000ffffc0a80001
return unless $ip =~ /^[:a-fz\d]+$/i;


my @h = split(/:/, $ip);
::ffff:71.19.147.227
return if @h + $omits > $len; # too many segments
IPv6: 00000000000000000000ffff471393e3


@h = map( $_ eq 'z' ? (0) x ($len - @h + 1) : ($_), @h);
[::ffff:71.19.147.227]:80
return join('' => map(sprintf("%04x", hex($_)), @h)).$v4;
IPv6: 00000000000000000000ffff471393e3
}
Port: 80


sub parse_ip {
::
my $str = shift;
BOGUS!
$str =~ s/^\s*//;
$str =~ s/\s*$//;


if ($str =~ s/^((?:\d+\.)+\d+)(?::(\d+))?$//) {
256.0.0.0
return 'v4', parse_v4($1, $2);
BOGUS!
}


my ($ip, $port);
g::1
if ($str =~ /^\[(.*?)\]:(\d+)$/) {
BOGUS!
$port = $2;
$ip = parse_v6($1);
} else {
$port = -1;
$ip = parse_v6($str);
}


return unless $ip;
0000
return 'v6', $ip, $port;
BOGUS!
}


for (qw/127.0.0.1 127.0.0.1:80
0000:0000
BOGUS!
::1
[::1]:80
2605:2700:0:3::4713:93e3
[2605:2700:0:3::4713:93e3]:80
::ffff:192.168.0.1
[::ffff:192.168.0.1]:22
::ffff:127.0.0.0.1
a::b::1/)
{
print "$_\n\t";
my ($ver, $ip, $port) = parse_ip($_)
or print "parse error\n" and next;


print "$ver $ip\tport $port\n\n";
0000:0000:0000:0000:0000:0000:0000:0000
}</syntaxhighlight>output<syntaxhighlight lang="text">127.0.0.1
IPv6: 00000000000000000000000000000000
v4 7f000001 port -1


127.0.0.1:80
0000:0000:0000::0000:0000
v4 7f000001 port 80
IPv6: 00000000000000000000000000000000


::1
0000::0000::0000:0000
v6 00000000000000000000000000000001 port -1
IPv6: 00000000000000000000000000000000


[::1]:80
ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
v6 00000000000000000000000000000001 port 80
IPv6: ffffffffffffffffffffffffffffffff


2605:2700:0:3::4713:93e3
ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff
v6 260527000000000300000000471393e3 port -1
BOGUS!


[2605:2700:0:3::4713:93e3]:80
fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
v6 260527000000000300000000471393e3 port 80
IPv6: 0fffffffffffffffffffffffffffffff


::ffff:192.168.0.1
fff:ffff:0:ffff:ffff:ffff:ffff:ffff
v6 00000000000000000000ffffc0a80001 port -1
IPv6: 0fffffff0000ffffffffffffffffffff</pre>

[::ffff:192.168.0.1]:22
v6 00000000000000000000ffffc0a80001 port 22

::ffff:127.0.0.0.1
parse error
a::b::1
parse error</syntaxhighlight>

=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">parse_ip</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">txt</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">r</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">dot</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">colon</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">':'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">openbr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'['</span><span style="color: #0000FF;">,</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">closebr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">']'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">colon</span><span style="color: #0000FF;">=</span><span style="color: #000000;">5</span> <span style="color: #008080;">and</span> <span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">4</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"http"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">or</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">colon</span><span style="color: #0000FF;">=</span><span style="color: #000000;">6</span> <span style="color: #008080;">and</span> <span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">5</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"https"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">txt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim</span><span style="color: #0000FF;">(</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">colon</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$],</span><span style="color: #008000;">"/"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">parse_ip</span><span style="color: #0000FF;">(</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">ipv6</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">openbr</span> <span style="color: #008080;">or</span> <span style="color: #000000;">dot</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">colon</span> <span style="color: #008080;">and</span> <span style="color: #000000;">colon</span><span style="color: #0000FF;"><</span><span style="color: #000000;">dot</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ipv6</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">openbr</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">openbr</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">or</span> <span style="color: #000000;">closebr</span><span style="color: #0000FF;"><</span><span style="color: #000000;">openbr</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">scanf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">closebr</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$],</span><span style="color: #008000;">":%d"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">port</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">port</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #000000;">port</span><span style="color: #0000FF;">></span><span style="color: #000000;">65535</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">port</span>
<span style="color: #000000;">txt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..</span><span style="color: #000000;">closebr</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">dot</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">colon</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">rfind</span><span style="color: #0000FF;">(</span><span style="color: #008000;">':'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">colon</span><span style="color: #0000FF;">></span><span style="color: #000000;">dot</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">r4</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">parse_ip</span><span style="color: #0000FF;">(</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">colon</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$])</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #004080;">sequence</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r4</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">or</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r4</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">4</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">7</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">r4</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">#100</span><span style="color: #0000FF;">+</span><span style="color: #000000;">r4</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">8</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">r4</span><span style="color: #0000FF;">[</span><span style="color: #000000;">3</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">#100</span><span style="color: #0000FF;">+</span><span style="color: #000000;">r4</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">txt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">colon</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">+(</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">colon</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">':'</span><span style="color: #0000FF;">)]</span>
<span style="color: #000000;">dot</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">r8</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ip</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">colon</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">':'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">colon</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ip</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">ip</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r8</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span>
<span style="color: #000000;">txt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">+(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r8</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)..$]</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">scanf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">colon</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #008000;">"%x"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">r11</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">r11</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #000000;">r11</span><span style="color: #0000FF;">></span><span style="color: #000000;">#FFFF</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">r8</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">r11</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">colon</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">txt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">colon</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ip</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r8</span><span style="color: #0000FF;">)>=(</span><span style="color: #000000;">8</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dot</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">r8</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ip</span><span style="color: #0000FF;">..</span><span style="color: #000000;">ip</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,(</span><span style="color: #000000;">8</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dot</span><span style="color: #0000FF;">)-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r8</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r8</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">8</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dot</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">8</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dot</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">r8</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">-- ipv4:</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">dot</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">colon</span> <span style="color: #008080;">and</span> <span style="color: #000000;">colon</span><span style="color: #0000FF;"><</span><span style="color: #000000;">dot</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">d4</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">colon</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">scanf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d4</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%d %d %d %d"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]<</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]></span><span style="color: #000000;">255</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">colon</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">r2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">scanf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">[</span><span style="color: #000000;">colon</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$],</span><span style="color: #008000;">"%d"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r2</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">port</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">r2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">port</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">or</span> <span style="color: #000000;">port</span><span style="color: #0000FF;">></span><span style="color: #000000;">65535</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">port</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">r</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #008000;">"127.0.0.1"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">127</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"127.0.0.1:80"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">127</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">80</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"::1"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"[::1]:80"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">80</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"2605:2700:0:3::4713:93e3"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#2605</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#2700</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#4713</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#93e3</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"[2605:2700:0:3::4713:93e3]:80"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#2605</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#2700</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#4713</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#93e3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">80</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"::ffff:192.168.173.22"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#c0a8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ad16</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"[::ffff:192.168.173.22]:80"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#c0a8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ad16</span><span style="color: #0000FF;">,</span><span style="color: #000000;">80</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"1::"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"[1::]:80"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">80</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"::"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"[::]:80"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">80</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"192.168.0.1"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">192</span><span style="color: #0000FF;">,</span><span style="color: #000000;">168</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"2001:db8:85a3:0:0:8a2e:370:7334"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#2001</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#db8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#85a3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#8a2e</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#370</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#7334</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"2001:db8:85a3::8a2e:370:7334"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#2001</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#db8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#85a3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#8a2e</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#370</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#7334</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"[2001:db8:85a3:8d3:1319:8a2e:370:7334]:443"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#2001</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#db8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#85a3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#8d3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#1319</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#8a2e</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#370</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#7334</span><span style="color: #0000FF;">,</span><span style="color: #000000;">443</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"256.0.0.0"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"g::1"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"::ffff:127.0.0.0.1"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"a::b::1"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"0000"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"0000:0000"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"0000:0000:0000:0000:0000:0000:0000:0000"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"0000:0000:0000::0000:0000"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"0000::0000::0000:0000"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#fff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"fff:ffff:0:ffff:ffff:ffff:ffff:ffff"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#fff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"2001:0db8:0:0:0:0:1428:57ab"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#2001</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#0db8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#1428</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#57ab</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"2001:0db8::1428:57ab"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#2001</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#0db8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#1428</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#57ab</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"2001:0db8:0:0:8d3:0:0:0"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#2001</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#0db8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#8d3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"2001:0db8:0:0:8d3::"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#2001</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#0db8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#8d3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"2001:0db8::8d3:0:0:0"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#2001</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#0db8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#8d3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"http://127.0.0.1/"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">127</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"https://127.0.0.1/"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">127</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"http:"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"http:/2001:db8:3:4::127.0.2.0"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">#2001</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#db8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#7F00</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#200</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"::192.168.0.1"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#C0A8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"::ffff:0:255.255.255.255"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">,</span><span style="color: #000000;">#ffff</span><span style="color: #0000FF;">}},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">""</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ffffffffffffffffffffffffffffffff::"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"[1::]:9999999999999999999999999999"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"I think that's enough tests for now"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #0000FF;">{</span><span style="color: #004080;">string</span> <span style="color: #000000;">ip</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">object</span> <span style="color: #000000;">expected</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">actual</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">parse_ip</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ip</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">actual</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">expected</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">?{</span><span style="color: #000000;">ip</span><span style="color: #0000FF;">,</span><span style="color: #000000;">actual</span><span style="color: #0000FF;">,</span><span style="color: #000000;">expected</span><span style="color: #0000FF;">}</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">addr</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">actual</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">addr</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"**not a valid ip address**"</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">actual</span><span style="color: #0000FF;">),</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">actual</span><span style="color: #0000FF;">[$]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">", port %d"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">actual</span><span style="color: #0000FF;">[$])</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">actual</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">actual</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">actual</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">5</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">addr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"ivp4 address: %02x%02x%02x%02x%s"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">actual</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">actual</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">9</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">addr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"ivp6 address: %04x%04x%04x%04x%04x%04x%04x%04x%s"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">actual</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<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;">"%45s %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ip</span><span style="color: #0000FF;">,</span><span style="color: #000000;">addr</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
                                    127.0.0.1 ivp4 address: 7F000001
                                 127.0.0.1:80 ivp4 address: 7F000001, port 80
                                          ::1 ivp6 address: 00000000000000000000000000000001
                                     [::1]:80 ivp6 address: 00000000000000000000000000000001, port 80
                     2605:2700:0:3::4713:93e3 ivp6 address: 260527000000000300000000471393E3
                [2605:2700:0:3::4713:93e3]:80 ivp6 address: 260527000000000300000000471393E3, port 80
                        ::ffff:192.168.173.22 ivp6 address: 00000000000000000000FFFFC0A8AD16
                   [::ffff:192.168.173.22]:80 ivp6 address: 00000000000000000000FFFFC0A8AD16, port 80
                                          1:: ivp6 address: 00010000000000000000000000000000
                                     [1::]:80 ivp6 address: 00010000000000000000000000000000, port 80
                                           :: ivp6 address: 00000000000000000000000000000000
                                      [::]:80 ivp6 address: 00000000000000000000000000000000, port 80
                                  192.168.0.1 ivp4 address: C0A80001
              2001:db8:85a3:0:0:8a2e:370:7334 ivp6 address: 20010DB885A3000000008A2E03707334
                 2001:db8:85a3::8a2e:370:7334 ivp6 address: 20010DB885A3000000008A2E03707334
   [2001:db8:85a3:8d3:1319:8a2e:370:7334]:443 ivp6 address: 20010DB885A308D313198A2E03707334, port 443
                                    256.0.0.0 **not a valid ip address**
                                         g::1 **not a valid ip address**
                           ::ffff:127.0.0.0.1 **not a valid ip address**
                                      a::b::1 **not a valid ip address**
                                         0000 **not a valid ip address**
                                    0000:0000 **not a valid ip address**
      0000:0000:0000:0000:0000:0000:0000:0000 ivp6 address: 00000000000000000000000000000000
                    0000:0000:0000::0000:0000 ivp6 address: 00000000000000000000000000000000
                        0000::0000::0000:0000 **not a valid ip address**
      ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ivp6 address: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
      ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff **not a valid ip address**
       fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ivp6 address: 0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
          fff:ffff:0:ffff:ffff:ffff:ffff:ffff ivp6 address: 0FFFFFFF0000FFFFFFFFFFFFFFFFFFFF
                  2001:0db8:0:0:0:0:1428:57ab ivp6 address: 20010DB80000000000000000142857AB
                         2001:0db8::1428:57ab ivp6 address: 20010DB80000000000000000142857AB
                      2001:0db8:0:0:8d3:0:0:0 ivp6 address: 20010DB80000000008D3000000000000
                          2001:0db8:0:0:8d3:: ivp6 address: 20010DB80000000008D3000000000000
                         2001:0db8::8d3:0:0:0 ivp6 address: 20010DB80000000008D3000000000000
                            http://127.0.0.1/ ivp4 address: 7F000001
                           https://127.0.0.1/ ivp4 address: 7F000001
                                        http: **not a valid ip address**
                http:/2001:db8:3:4::127.0.2.0 ivp6 address: 20010DB800030004000000007F000200
                                ::192.168.0.1 ivp6 address: 000000000000000000000000C0A80001
                     ::ffff:0:255.255.255.255 ivp6 address: 0000000000000000FFFF0000FFFFFFFF
                                              **not a valid ip address**
           ffffffffffffffffffffffffffffffff:: **not a valid ip address**
           [1::]:9999999999999999999999999999 **not a valid ip address**
          I think that's enough tests for now **not a valid ip address**
</pre>


=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
<lang PicoLisp># Return a cons pair of address and port: (address . port)
<syntaxhighlight lang="picolisp"># Return a cons pair of address and port: (address . port)
(de ipAddress (Adr)
(de ipAddress (Adr)
(use (@A @B @C @D @Port)
(use (@A @B @C @D @Port)
Line 1,399: Line 2,464:
(need (- 9 (length Lst)) 0) ) ) # Handle '::'
(need (- 9 (length Lst)) 0) ) ) # Handle '::'
(cons (or (car Lst) "0") (cdr Lst)) ) )
(cons (or (car Lst) "0") (cdr Lst)) ) )
(format Port) ) )</lang>
(format Port) ) )</syntaxhighlight>
Test:
Test:
<lang PicoLisp>(for A
<syntaxhighlight lang="picolisp">(for A
(quote
(quote
"127.0.0.1"
"127.0.0.1"
Line 1,414: Line 2,479:
(hex (car I))
(hex (car I))
(format (car I))
(format (car I))
(cdr I) ) ) )</lang>
(cdr I) ) ) )</syntaxhighlight>
Output:
Output:
<pre style="height:8em;overflow:scroll">127.0.0.1 7F000001 2130706433
<pre style="height:8em;overflow:scroll">127.0.0.1 7F000001 2130706433
Line 1,424: Line 2,489:


==PL/I==
==PL/I==
<lang pli>*process or(!) source xref attributes macro options;
<syntaxhighlight lang="pli">*process or(!) source xref attributes macro options;
/*********************************************************************
/*********************************************************************
* Program to parse an IP address into --> IPv4 or IPv6 format
* Program to parse an IP address into --> IPv4 or IPv6 format
Line 1,700: Line 2,765:
End;
End;


end;</lang>
end;</syntaxhighlight>
Output:
Output:
<pre style="overflow:scroll">
<pre style="overflow:scroll">
Line 1,712: Line 2,777:
::1 00000000000000000000000000000001 1 IPv6
::1 00000000000000000000000000000001 1 IPv6
[::1]:80 00000000000000000000000000000001 1 IPv6 80</pre>
[::1]:80 00000000000000000000000000000001 1 IPv6 80</pre>

=={{header|PowerShell}}==
<syntaxhighlight lang="powershell">
function Get-IpAddress
{
[CmdletBinding()]
[OutputType([PSCustomObject])]
Param
(
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
$InputObject
)

Begin
{
function Get-Address ([string]$Address)
{
if ($Address.IndexOf(".") -ne -1)
{
$Address, $port = $Address.Split(":")

[PSCustomObject]@{
IPAddress = [System.Net.IPAddress]$Address
Port = $port
}
}
else
{
if ($Address.IndexOf("[") -ne -1)
{
[PSCustomObject]@{
IPAddress = [System.Net.IPAddress]$Address
Port = ($Address.Split("]")[-1]).TrimStart(":")
}
}
else
{
[PSCustomObject]@{
IPAddress = [System.Net.IPAddress]$Address
Port = $null
}
}
}
}
}
Process
{
$InputObject | ForEach-Object {
$address = Get-Address $_
$bytes = ([System.Net.IPAddress]$address.IPAddress).GetAddressBytes()
[Array]::Reverse($bytes)
$i = 0
$bytes | ForEach-Object -Begin {[bigint]$decimalIP = 0} `
-Process {$decimalIP += [bigint]$_ * [bigint]::Pow(256, $i); $i++} `
-End {[PSCustomObject]@{
Address = $address.IPAddress
Port = $address.Port
Hex = "0x$($decimalIP.ToString('x'))"}
}
}
}
}
</syntaxhighlight>
Parse an array of IP addresses in a text format:
<syntaxhighlight lang="powershell">
$ipAddresses = "127.0.0.1","127.0.0.1:80","::1","[::1]:80","2605:2700:0:3::4713:93e3","[2605:2700:0:3::4713:93e3]:80" | Get-IpAddress
$ipAddresses
</syntaxhighlight>
{{Out}}
<pre>
Address Port Hex
------- ---- ---
127.0.0.1 0x7f000001
127.0.0.1 80 0x7f000001
::1 0x1
::1 80 0x1
2605:2700:0:3::4713:93e3 0x260527000000000300000000471393e3
2605:2700:0:3::4713:93e3 80 0x260527000000000300000000471393e3
</pre>
The '''Address''' "property" is an object containing more information...
<syntaxhighlight lang="powershell">
$ipAddresses[5].Address
</syntaxhighlight>
{{Out}}
<pre>
Address :
AddressFamily : InterNetworkV6
ScopeId : 0
IsIPv6Multicast : False
IsIPv6LinkLocal : False
IsIPv6SiteLocal : False
IsIPv6Teredo : False
IsIPv4MappedToIPv6 : False
IPAddressToString : 2605:2700:0:3::4713:93e3
</pre>
... allowing for specific filtering:
<syntaxhighlight lang="powershell">
$ipAddresses | where {$_.Address.AddressFamily -eq "InterNetworkV6" -and $_.Port -ne $null}
</syntaxhighlight>
{{Out}}
<pre>
Address Port Hex
------- ---- ---
::1 80 0x1
2605:2700:0:3::4713:93e3 80 0x260527000000000300000000471393e3
</pre>


=={{header|Python}}==
=={{header|Python}}==
===Python: Using ipaddress===
{{works with|Python|3.5}}
<syntaxhighlight lang="python">from ipaddress import ip_address
from urllib.parse import urlparse

tests = [
"127.0.0.1",
"127.0.0.1:80",
"::1",
"[::1]:80",
"::192.168.0.1",
"2605:2700:0:3::4713:93e3",
"[2605:2700:0:3::4713:93e3]:80" ]

def parse_ip_port(netloc):
try:
ip = ip_address(netloc)
port = None
except ValueError:
parsed = urlparse('//{}'.format(netloc))
ip = ip_address(parsed.hostname)
port = parsed.port
return ip, port

for address in tests:
ip, port = parse_ip_port(address)
hex_ip = {4:'{:08X}', 6:'{:032X}'}[ip.version].format(int(ip))
print("{:39s} {:>32s} IPv{} port={}".format(
str(ip), hex_ip, ip.version, port ))</syntaxhighlight>

{{out}}
<pre>
127.0.0.1 7F000001 IPv4 port=None
127.0.0.1 7F000001 IPv4 port=80
::1 00000000000000000000000000000001 IPv6 port=None
::1 00000000000000000000000000000001 IPv6 port=80
::c0a8:1 000000000000000000000000C0A80001 IPv6 port=None
2605:2700:0:3::4713:93e3 260527000000000300000000471393E3 IPv6 port=None
2605:2700:0:3::4713:93e3 260527000000000300000000471393E3 IPv6 port=80
</pre>
===Python: Using pyparsing===
{{libheader|pyparse}}
{{libheader|pyparse}}
The following uses [http://pyparsing.wikispaces.com/ pyparse] to parse the IP address. It's an attempt at using pyparse to describe an IP address in an ''extended'' [[wp:Backus–Naur_Form|BNF syntax]]. Using a parser does seems a bit like using a sledgehammer to crack a nut. However it does make for an interesting alternative to using a [[Regular expression|regular expressions]] to parse IP addresses. Note - for example - that the parser specifically reports - as an exception - the location where the IP address is syntactically wrong.
The following uses [http://pyparsing.wikispaces.com/ pyparse] to parse the IP address. It's an attempt at using pyparse to describe an IP address in an ''extended'' [[wp:Backus–Naur_Form|BNF syntax]]. Using a parser does seems a bit like using a sledgehammer to crack a nut. However it does make for an interesting alternative to using a [[Regular expression|regular expressions]] to parse IP addresses. Note - for example - that the parser specifically reports - as an exception - the location where the IP address is syntactically wrong.
<lang python>import string
<syntaxhighlight lang="python">import string
from pyparsing import * # import antigravity
from pyparsing import * # import antigravity


Line 1,839: Line 3,054:
print ip, "IP Version:",ip.version,"- Address is OK!",
print ip, "IP Version:",ip.version,"- Address is OK!",
except (ParseException,ValueError), details: print "Bad! IP address syntax error detected:",details,
except (ParseException,ValueError), details: print "Bad! IP address syntax error detected:",details,
print "- Actually:",desc</lang>
print "- Actually:",desc</syntaxhighlight>
Output:
Output:
<pre>
<pre>
Line 1,882: Line 3,097:


=={{header|Racket}}==
=={{header|Racket}}==
<lang racket>
<syntaxhighlight lang="racket">
#lang racket
#lang racket


Line 1,912: Line 3,127:
"2605:2700:0:3::4713:93e3"
"2605:2700:0:3::4713:93e3"
"[2605:2700:0:3::4713:93e3]:80"))
"[2605:2700:0:3::4713:93e3]:80"))
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 1,922: Line 3,137:
[2605:2700:0:3::4713:93e3]:80 260527000000000300000000471393e3 ipv6 80
[2605:2700:0:3::4713:93e3]:80 260527000000000300000000471393e3 ipv6 80
</pre>
</pre>

=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>grammar IP_Addr {
token TOP { ^ [ <IPv4> | <IPv6> ] $ }
token IPv4 {
[ <d8> +% '.' ] <?{ $<d8> == 4 }> <port>?
{ @*by8 = @$<d8> }
}

token IPv6 {
| <ipv6>
| '[' <ipv6> ']' <port>
}

token ipv6 {
| <h16> +% ':' <?{ $<h16> == 8 }>
{ @*by16 = @$<h16> }
| [ (<h16>) +% ':']? '::' [ (<h16>) +% ':' ]? <?{ @$0 + @$1 ≤ 8 }>
{ @*by16 = |@$0, |('0' xx 8 - (@$0 + @$1)), |@$1 }
| '::ffff:' <IPv4>
{ @*by16 = |('0' xx 5), 'ffff', |(by8to16 @*by8) }
}

token d8 { (\d+) <?{ $0 < 256 }> }
token d16 { (\d+) <?{ $0 < 65536 }> }
token h16 { (<xdigit>+) <?{ $0.chars ≤ 4 }> }

token port {
':' <d16> { $*port = +$<d16> }
}
}

sub by8to16 (@m) { gather for @m -> $a,$b { take ($a * 256 + $b).fmt("%04x") } }

my @cases = <
127.0.0.1
127.0.0.1:80
::1
[::1]:80
2605:2700:0:3::4713:93e3
[2605:2700:0:3::4713:93e3]:80
2001:db8:85a3:0:0:8a2e:370:7334
2001:db8:85a3::8a2e:370:7334
[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443
192.168.0.1
::ffff:192.168.0.1
::ffff:71.19.147.227
[::ffff:71.19.147.227]:80
::
256.0.0.0
g::1
0000
0000:0000
0000:0000:0000:0000:0000:0000:0000:0000
0000:0000:0000::0000:0000
0000::0000::0000:0000
ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff
fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
fff:ffff:0:ffff:ffff:ffff:ffff:ffff
>;

for @cases -> $addr {
my @*by8;
my @*by16;
my $*port;

IP_Addr.parse($addr);

say $addr;
if @*by16 {
say " IPv6: ", @*by16.map({:16(~$_)})».fmt("%04x").join;
say " Port: ", $*port if $*port;
}
elsif @*by8 {
say " IPv4: ", @*by8».fmt("%02x").join;
say " Port: ", $*port if $*port;
}
else {
say " BOGUS!";
}
say '';
}</syntaxhighlight>
{{out}}
<pre>127.0.0.1
IPv4: 7f000001

127.0.0.1:80
IPv4: 7f000001
Port: 80

::1
IPv6: 00000000000000000000000000000001

[::1]:80
IPv6: 00000000000000000000000000000001
Port: 80

2605:2700:0:3::4713:93e3
IPv6: 260527000000000300000000471393e3

[2605:2700:0:3::4713:93e3]:80
IPv6: 260527000000000300000000471393e3
Port: 80

2001:db8:85a3:0:0:8a2e:370:7334
IPv6: 20010db885a3000000008a2e03707334

2001:db8:85a3::8a2e:370:7334
IPv6: 20010db885a3000000008a2e03707334

[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443
IPv6: 20010db885a308d313198a2e03707348
Port: 443

192.168.0.1
IPv4: c0a80001

::ffff:192.168.0.1
IPv6: 00000000000000000000ffffc0a80001

::ffff:71.19.147.227
IPv6: 00000000000000000000ffff471393e3

[::ffff:71.19.147.227]:80
IPv6: 00000000000000000000ffff471393e3
Port: 80

::
IPv6: 00000000000000000000000000000000

256.0.0.0
BOGUS!

g::1
BOGUS!

0000
BOGUS!

0000:0000
BOGUS!

0000:0000:0000:0000:0000:0000:0000:0000
IPv6: 00000000000000000000000000000000

0000:0000:0000::0000:0000
IPv6: 00000000000000000000000000000000

0000::0000::0000:0000
IPv6: 00000000000000000000000000000000

ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
IPv6: ffffffffffffffffffffffffffffffff

ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff
BOGUS!

fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
IPv6: 0fffffffffffffffffffffffffffffff

fff:ffff:0:ffff:ffff:ffff:ffff:ffff
IPv6: 0fffffff0000ffffffffffffffffffff</pre>


=={{header|REXX}}==
=={{header|REXX}}==
One of REXX's strongest features is its ability for parsing, it has PARSE instruction for this purpose.
One of REXX's strongest features is its ability for parsing, &nbsp; it has
the &nbsp; '''parse''' &nbsp; instruction for this purpose.
===version 1===
=== version 1 ===
<lang rexx>/*REXX program to parse an IP address into ──► IPv4 or IPv6 format, port*/
<syntaxhighlight lang="rexx">/*REXX program parses an IP address into ──► IPv4 or IPv6 format, optional pport.*/
say center('input IP address' ,30),
center('hex IP address' ,32),
_= "_"; say center('input IP address' , 30),
center('decimal IP address' ,39) 'space port'
center('hex IP address' , 32),
center('decimal IP address' , 39) "space port"
_='─'
say copies(_,30) copies(_,32) copies(_,39) copies(_,5) copies(_,5)
say copies(_, 30) copies(_, 32) copies(_, 39) copies(_, 5) copies(_, 5)
call IP_parse 127.0.0.1 /*this IP doesn't need quotes. */
call IP_parse 127.0.0.1 /*this simple IP doesn't need quotes.*/
call IP_parse '127.0.0.1:80'
call IP_parse '127.0.0.1:80'
call IP_parse '::1'
call IP_parse '::1'
Line 1,938: Line 3,320:
call IP_parse '2605:2700:0:3::4713:93e3'
call IP_parse '2605:2700:0:3::4713:93e3'
call IP_parse '[2605:2700:0:3::4713:93e3]:80'
call IP_parse '[2605:2700:0:3::4713:93e3]:80'
exit /*stick a fork in it, we're done.*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────IP_parse subroutine─────────────────*/
IP_parse: procedure; parse arg a .; hx=; @.=; numeric digits 50
IP_parse: procedure; parse arg a .; hx=; @.=; numeric digits 50
dot=pos('.',a)\==0 /*see if there is a dot present. */
dot= pos(., a)\==0 /*see if there is a dot present in IP. */


if dot then do; parse var a @.1 '.' @.2 "." @.3 '.' @.4 ":" port
if dot then do; parse var a @.1 '.' @.2 "." @.3 '.' @.4 ":" port
do j=1 for 4; hx=hx || d2x(@.j,2)
do j=1 for 4; hx= hx || d2x(@.j, 2)
end /*j*/
end /*j*/
end /*if dot*/
end
else do; parse var a pureA ']:' port
else do; parse var a pureA ']:' port
_=space(translate(pureA,,'[]'),0) /*remove brackets*/
_= space( translate( pureA, , '[]'), 0) /*remove brackets.*/
parse var _ x '::' y
parse var _ x '::' y
do L=1 until x=='' /*get left side.*/
do L=1 until x=='' /*get left side. */
parse var x @.L ':' x
parse var x @.L ':' x
end /*L*/
end /*L*/
y=reverse(y)
y= reverse(y)
do r=8 by -1 /*get right side.*/
do r=8 by -1 /*get right side. */
parse var y z ':' y; if z=='' then leave
parse var y z ':' y; if z=='' then leave
@.r=reverse(z)
@.r= reverse(z)
end /*r*/
end /*r*/


do k=1 for 8; hx=hx || right(word(@.k 0, 1), 4, 0)
do k=1 for 8; hx=hx || right( word(@.k 0, 1), 4, 0)
end /*k*/
end /*k*/
end /*else dot*/
end


say left(a,30) right(hx,32) right(x2d(hx),39) ' IPv'||(6-2*dot) right(port,5)
say left(a,30) right(hx,32) right(x2d(hx),39) ' IPv' || (6-2*dot) right(port,5)
return</lang>
return</syntaxhighlight>
'''output''' using the default input
{{out|output|text=&nbsp; when using the internal default input:}}
<pre>
<pre style="overflow:scroll">
input IP address hex IP address decimal IP address space port
input IP address hex IP address decimal IP address space port
────────────────────────────── ──────────────────────────────── ─────────────────────────────────────── ───── ─────
────────────────────────────── ──────────────────────────────── ─────────────────────────────────────── ───── ─────
Line 1,977: Line 3,359:
</pre>
</pre>


===version 2===
=== version 2 ===
<lang rexx>/* REXX ***************************************************************
<syntaxhighlight lang="rexx">/* REXX ***************************************************************
* 27.05.2013 Walter Pachl
* 27.05.2013 Walter Pachl
**********************************************************************/
**********************************************************************/
Line 2,060: Line 3,442:
End
End
End
End
Return o2 'IPv6' port</lang>
Return o2 'IPv6' port</syntaxhighlight>
Output:
Output:
<pre style="overflow:scroll">
<pre style="overflow:scroll">
Line 2,084: Line 3,466:
=={{header|Ruby}}==
=={{header|Ruby}}==


<syntaxhighlight lang="ruby">require 'ipaddr'
Ruby 1.9.2 has better IPv6 support than older versions. This script uses class Addrinfo from Ruby 1.9.2.


{{works with|Ruby|1.9.2}}
TESTCASES = ["127.0.0.1", "127.0.0.1:80",
<lang ruby>require 'socket'
require 'ipaddr'

IP_ADDRESSES = ["127.0.0.1", "127.0.0.1:80",
"::1", "[::1]:80",
"::1", "[::1]:80",
"2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80",
"2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80"]
"fe80::1%lo0", "1600 Pennsylvania Avenue NW"]
output = []
output << %w(String Address Port Family Hex Scope?)
output << %w(------ ------- ---- ------ --- ------)


output = [%w(String Address Port Family Hex),
# Parse _string_ for an IP address and optional port number. Returns
%w(------ ------- ---- ------ ---)]
# them in an Addrinfo object.

def parse_addr(string)
def output_table(rows)
# Split host and port number from string.
widths = []
case string
rows.each {|row| row.each_with_index {|col, i| widths[i] = [widths[i].to_i, col.to_s.length].max }}
format = widths.map {|size| "%#{size}s"}.join("\t")
rows.each {|row| puts format % row}
end

TESTCASES.each do |str|
case str # handle port; IPAddr does not.
when /\A\[(?<address> .* )\]:(?<port> \d+ )\z/x # string like "[::1]:80"
when /\A\[(?<address> .* )\]:(?<port> \d+ )\z/x # string like "[::1]:80"
address, port = $~[:address], $~[:port]
address, port = $~[:address], $~[:port]
Line 2,108: Line 3,490:
address, port = $~[:address], $~[:port]
address, port = $~[:address], $~[:port]
else # string with no port number
else # string with no port number
address, port = string, nil
address, port = str, nil
end
end
ip_addr = IPAddr.new(address)
family = "IPv4" if ip_addr.ipv4?
family = "IPv6" if ip_addr.ipv6?


output << [str, ip_addr.to_s, port.to_s, family, ip_addr.to_i.to_s(16)]
# Pass address, port to Addrinfo.getaddrinfo. It will raise SocketError if address or port is not valid.
# IPAddr currently cannot handle ::1 notation, use Addrinfo instead
ary = Addrinfo.getaddrinfo(address, port)

# An IP address is exactly one address.
ary.size == 1 or raise SocketError, "expected 1 address, found #{ary.size}"
ary.first
end
end


def output_table(rows)
output_table(output)</syntaxhighlight>
{{Output}}
widths = []
<pre> String Address Port Family Hex
rows.each {|row| row.each_with_index {|col, i| widths[i] = [widths[i].to_i, col.to_s.length].max }}
------ ------- ---- ------ ---
format = widths.map {|size| "%#{size}s"}.join("\t")
127.0.0.1 127.0.0.1 IPv4 7f000001
rows.each {|row| puts format % row}
127.0.0.1:80 127.0.0.1 80 IPv4 7f000001
end
::1 ::1 IPv6 1
[::1]:80 ::1 80 IPv6 1
2605:2700:0:3::4713:93e3 2605:2700:0:3::4713:93e3 IPv6 260527000000000300000000471393e3
[2605:2700:0:3::4713:93e3]:80 2605:2700:0:3::4713:93e3 80 IPv6 260527000000000300000000471393e3
</pre>


=={{header|Rust}}==
family_hash = {Socket::AF_INET => "ipv4", Socket::AF_INET6 => "ipv6"}
<syntaxhighlight lang="rust">use std::{
net::{IpAddr, SocketAddr},
str::FromStr,
};


#[derive(Clone, Debug)]
IP_ADDRESSES.each do |string|
struct Addr {
begin
addr = parse_addr(string)
addr: IpAddr,
port: Option<u16>,
rescue SocketError
}
output << [string, "illegal address", '','','','']
else
(cur_string ||= []) << string << addr.ip_address << addr.ip_port.to_s << family_hash[addr.afamily] # for output


impl std::fmt::Display for Addr {
# Show address in hexadecimal. We must unpack it from sockaddr string.
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if addr.ipv4?
let ipv = if self.addr.is_ipv4() { "4" } else { "6" };
# network byte order "N"
cur_string << "0x%08x" % IPAddr.new(addr.ip_address).hton.unpack('N') << ""
elsif addr.ipv6?
# 32 bytes for address, network byte order "N4"
cur_string << "0x%032x" % IPAddr.new(addr.ip_address).to_i
cur_string << (addr.ipv6_linklocal? ? ary[4] : "") # for Scope
end
output << cur_string
end
end


let hex = match self.addr {
output_table output
IpAddr::V4(addr) => u32::from(addr) as u128,
</lang>
IpAddr::V6(addr) => u128::from(addr),
};


match self.port {
<pre> String Address Port Family Hex Scope?
Some(p) => write!(
------ ------- ---- ------ --- ------
f,
127.0.0.1 127.0.0.1 0 ipv4 0x7f000001
"address: {}, port: {}, hex: {:x} (IPv{})",
127.0.0.1:80 127.0.0.1 80 ipv4 0x7f000001
self.addr, p, hex, ipv
::1 ::1 0 ipv6 0x00000000000000000000000000000001
),
[::1]:80 ::1 80 ipv6 0x00000000000000000000000000000001

2605:2700:0:3::4713:93e3 2605:2700:0:3::4713:93e3 0 ipv6 0x260527000000000300000000471393e3
None => write!(
[2605:2700:0:3::4713:93e3]:80 2605:2700:0:3::4713:93e3 80 ipv6 0x260527000000000300000000471393e3
fe80::1%lo0 illegal address
f,
1600 Pennsylvania Avenue NW illegal address</pre>
"address: {}, port: N/A, hex: {:x} (IPv{}) ",
self.addr, hex, ipv
),
}
}
}

impl FromStr for Addr {
type Err = ();

fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(addr) = s.parse::<IpAddr>() {
Ok(Self { addr, port: None })
} else if let Ok(sock) = s.parse::<SocketAddr>() {
Ok(Self {
addr: sock.ip(),
port: Some(sock.port()),
})
} else {
Err(())
}
}
}

fn print_addr(s: &str) {
match s.parse::<Addr>() {
Ok(addr) => println!("{}: {}", s, addr),
_ => println!("{} not a valid address", s),
}
}

fn main() {
[
"127.0.0.1",
"127.0.0.1:80",
"::1",
"[::1]:80",
"2605:2700:0:3::4713:93e3",
"[2605:2700:0:3::4713:93e3]:80",
]
.iter()
.cloned()
.for_each(print_addr);
}</syntaxhighlight>

=={{header|Scala}}==
===Full blown ultimate solution===
{{Out}}Best seen running in your browser [https://scastie.scala-lang.org/kWO8C5pLSu6xEQ0kHAlswg Scastie (remote JVM)].
<syntaxhighlight lang="scala">object IPparser extends App {

/*
Parse an IP (v4/v6) Address

This software can parse all ipv4/ipv6 address text representations
of IP Address in common usage against the IEF RFC 5952 specification.

The results of the parse are:
- The parts of the text are valid representations. This is indicated in the list by a ✔ or ✘.
- The intended version; 4 or 6.
- Compliance with RFC 5952 in respect with double colons Compressed zeroes expansion ('::') and lower case letters.
- Hexadecimal representation of the intended IP address.
- If part in the text the port number which is optional.
- The used text string search pattern.

As much of the information is produced if there are invalid parts in the remark field.
*/

def myCases = Map(
"http:" -> IPInvalidAddressComponents(remark = "No match at all: 'http:'."),
"http://" -> IPInvalidAddressComponents(remark = "No match at all: 'http://'."),
"http:// " -> IPInvalidAddressComponents(remark = "No match at all: 'http:// '."),
"http://127.0.0.1/" -> ResultContainer(4, BigInt("7F000001", 16)),
"http://127.0.0.1:80/" -> ResultContainer(4, BigInt("7F000001", 16), Some(80)),
"http://127.0.0.1:65536" ->
IPInvalidAddressComponents(4, BigInt("7F000001", 16), Some(65536), remark = "Port number out of range."),
"http://192.168.0.1" -> ResultContainer(4, BigInt("C0A80001", 16)),
"http:/1::" -> ResultContainer(6, BigInt("10000000000000000000000000000", 16)),
"http:/2001:0db8:0:0:0:0:1428:57ab/" -> ResultContainer(6, BigInt("20010db80000000000000000142857ab", 16)),
"2001:0db8:0:0:8d3:0:0:0" -> ResultContainer(6, BigInt("20010db80000000008d3000000000000", 16)),
"2001:db8:0:0:8d3::" -> ResultContainer(6, BigInt("20010db80000000008d3000000000000", 16)),
"http:/2001:db8:3:4::192.0.2.33" -> ResultContainer(6, BigInt("20010db80003000400000000c0000221", 16)),
"2001:db8:85a3:0:0:8a2e:370:7334" -> ResultContainer(6, BigInt("20010db885a3000000008a2e03707334", 16)),
"2001:db8::1428:57ab" -> ResultContainer(6, BigInt("20010db80000000000000000142857ab", 16)),
"2001:db8::8d3:0:0:0" -> ResultContainer(6, BigInt("20010db80000000008d3000000000000", 16)),
"256.0.0.0" -> IPInvalidAddressComponents(4, remark = "Invalid octets."),
"2605:2700:0:3::4713:93e3" -> ResultContainer(6, BigInt("260527000000000300000000471393e3", 16)),
"::" -> ResultContainer(6, BigInt("00000000000000000000000000000000", 16)),
"1::8" -> ResultContainer(6, BigInt("00010000000000000000000000000008", 16)),
"::1" -> ResultContainer(6, BigInt("00000000000000000000000000000001", 16)),
"::192.168.0.1" -> ResultContainer(6, BigInt("000000000000000000000000c0a80001", 16)),
"::255.255.255.255" -> ResultContainer(6, BigInt("000000000000000000000000ffffffff", 16)),
"http:/[::255.255.255.255]:65536" ->
IPInvalidAddressComponents(6, BigInt("000000000000000000000000ffffffff", 16), Some(65536), remark = "Port number out of range."),
"::2:3:4:5:6:7:8" -> ResultContainer(6, BigInt("00000002000300040005000600070008", 16), strictRFC5952 = false),
"::8" -> ResultContainer(6, BigInt("00000000000000000000000000000008", 16)),
"::c0a8:1" -> ResultContainer(6, BigInt("000000000000000000000000c0a80001", 16)),
"::ffff:0:255.255.255.255" -> ResultContainer(6, BigInt("0000000000000000ffff0000ffffffff", 16)),
"::ffff:127.0.0.0.1" -> IPInvalidAddressComponents(4, remark = "Address puntation error: ':127.0.0.0.1'."),
"::ffff:127.0.0.1" -> ResultContainer(6, BigInt("00000000000000000000ffff7f000001", 16)),
"::ffff:192.168.0.1" -> ResultContainer(6, BigInt("00000000000000000000ffffc0a80001", 16)),
"::ffff:192.168.173.22" -> ResultContainer(6, BigInt("00000000000000000000ffffc0a8ad16", 16)),
"::ffff:255.255.255.255" -> ResultContainer(6, BigInt("00000000000000000000ffffffffffff", 16)),
"::ffff:71.19.147.227" -> ResultContainer(6, BigInt("00000000000000000000ffff471393e3", 16)),
"1:2:3:4:5:6:7::" -> ResultContainer(6, BigInt("00010002000300040005000600070000", 16), strictRFC5952 = false),
"8000:2:3:4:5:6:7::" -> ResultContainer(6, BigInt("80000002000300040005000600070000", 16), strictRFC5952 = false),
"1:2:3:4:5:6::8" -> ResultContainer(6, BigInt("00010002000300040005000600000008", 16), strictRFC5952 = false),
"1:2:3:4:5::8" -> ResultContainer(6, BigInt("00010002000300040005000000000008", 16)),
"1::7:8" -> ResultContainer(6, BigInt("00010000000000000000000000070008", 16)),
"a::b::1" -> IPInvalidAddressComponents(remark = "Noise found: 'a::b::1'."),
"fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" -> ResultContainer(6, BigInt("0fffffffffffffffffffffffffffffff", 16)),
"FFFF:ffff:ffff:ffff:ffff:ffff:ffff:ffff" -> ResultContainer(6, BigInt("ffffffffffffffffffffffffffffffff", 16), strictRFC5952 = false),
"ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff" -> IPInvalidAddressComponents(remark = "No match at all: 'ffff:ffff:ffff:fffg…'."),
"g::1" -> IPInvalidAddressComponents(6, remark ="Invalid input 'g::1'."),
"[g::1]:192.0.2.33" -> IPInvalidAddressComponents(4, remark = "Address puntation error: ':192.0.2.33'."),
"1:2:3:4:5:6:7:8" -> ResultContainer(6, BigInt("00010002000300040005000600070008", 16)),
"1:2:3:4:5::7:8" -> ResultContainer(6, BigInt("00010002000300040005000000070008", 16), strictRFC5952 = false),
"1:2:3:4::6:7:8" -> ResultContainer(6, BigInt("00010002000300040000000600070008", 16), strictRFC5952 = false),
"1:2:3:4::8" -> ResultContainer(6, BigInt("00010002000300040000000000000008", 16)),
"1:2:3::5:6:7:8" -> ResultContainer(6, BigInt("00010002000300000005000600070008", 16), strictRFC5952 = false),
"1:2:3::8" -> ResultContainer(6, BigInt("00010002000300000000000000000008", 16)),
"1:2::4:5:6:7:8" -> ResultContainer(6, BigInt("00010002000000040005000600070008", 16), strictRFC5952 = false),
"1:2::8" -> ResultContainer(6, BigInt("00010002000000000000000000000008", 16)),
"1::3:4:5:6:7:8" -> ResultContainer(6, BigInt("00010000000300040005000600070008", 16), strictRFC5952 = false),
"1::4:5:6:7:8" -> ResultContainer(6, BigInt("00010000000000040005000600070008", 16)),
"1::5:6:7:8" -> ResultContainer(6, BigInt("00010000000000000005000600070008", 16)),
"[1::6:7:8]" -> ResultContainer(6, BigInt("0010000000000000000000600070008", 16)),
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" -> ResultContainer(6, BigInt("ffffffffffffffffffffffffffffffff", 16)),
"64:ff9b::192.0.2.33" -> ResultContainer(6, BigInt("0064ff9b0000000000000000c0000221", 16)),
"64:ff9b::256.0.2.33" ->
IPInvalidAddressComponents(6, BigInt("0064ff9b000000000000000000000000", 16), remark = "Invalid octets."),
"[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443" -> ResultContainer(6, BigInt("20010db885a308d313198a2e03707348", 16), Some(443)),
"[2001:db8:85a3:8d3:1319:8a2e:370:7348]:100000" ->
IPInvalidAddressComponents(6, BigInt("20010db885a308d313198a2e03707348", 16), Some(100000), remark = "Port number out of range."),
"[2605:2700:0:3::4713:93e3]:80" -> ResultContainer(6, BigInt("260527000000000300000000471393e3", 16), Some(80)),
"[::ffff:192.168.0.1]:22" -> ResultContainer(6, BigInt("00000000000000000000ffffc0a80001", 16), Some(22)),
"[::ffff:192.168.173.22]:80" -> ResultContainer(6, BigInt("00000000000000000000ffffc0a8ad16", 16), Some(80)),
"[::ffff:71.19.147.227]:80" -> ResultContainer(6, BigInt("00000000000000000000FFFF471393E3", 16), Some(80)),
"2001:0DB8:0:0:0:0:1428:57AB" -> ResultContainer(6, BigInt("20010DB80000000000000000142857AB", 16), strictRFC5952 = false),
"2001:0DB8:0:0:8D3:0:0:0" -> ResultContainer(6, BigInt("20010DB80000000008D3000000000000", 16), strictRFC5952 = false),
"2001:DB8:0:0:8D3::" -> ResultContainer(6, BigInt("20010DB80000000008D3000000000000", 16), strictRFC5952 = false),
"2001:DB8:3:4::192.0.2.33" -> ResultContainer(6, BigInt("20010DB80003000400000000C0000221", 16), strictRFC5952 = false),
"2001:DB8:85A3:0:0:8A2E:370:7334" -> ResultContainer(6, BigInt("20010DB885A3000000008A2E03707334", 16), strictRFC5952 = false),
"2001:DB8::1428:57AB" -> ResultContainer(6, BigInt("20010DB80000000000000000142857AB", 16), strictRFC5952 = false),
"2001:DB8::8D3:0:0:0" -> ResultContainer(6, BigInt("20010DB80000000008D3000000000000", 16), strictRFC5952 = false),
"2605:2700:0:3::4713:93E3" -> ResultContainer(6, BigInt("260527000000000300000000471393E3", 16), strictRFC5952 = false),
"::192.168.0.1" -> ResultContainer(6, BigInt("000000000000000000000000C0A80001", 16)),
"::255.255.255.255" -> ResultContainer(6, BigInt("000000000000000000000000FFFFFFFF", 16)),
"::C0A8:1" -> ResultContainer(6, BigInt("000000000000000000000000c0a80001", 16), strictRFC5952 = false),
"::FFFF:0:255.255.255.255" -> ResultContainer(6, BigInt("0000000000000000FFFF0000FFFFFFFF", 16), strictRFC5952 = false),
"::FFFF:127.0.0.0.1" -> IPInvalidAddressComponents(4, remark = "Address puntation error: ':127.0.0.0.1'."),
"::FFFF:127.0.0.1" -> ResultContainer(6, BigInt("00000000000000000000FFFF7F000001", 16), strictRFC5952 = false),
"::FFFF:192.168.0.1" -> ResultContainer(6, BigInt("00000000000000000000FFFFC0A80001", 16), strictRFC5952 = false),
"::FFFF:192.168.173.22" -> ResultContainer(6, BigInt("00000000000000000000FFFFC0A8AD16", 16), strictRFC5952 = false),
"::FFFF:255.255.255.255" -> ResultContainer(6, BigInt("00000000000000000000FFFFFFFFFFFF", 16), strictRFC5952 = false),
"::FFFF:71.19.147.227" -> ResultContainer(6, BigInt("00000000000000000000FFFF471393E3", 16), strictRFC5952 = false),
"[1::]:80" -> ResultContainer(6, BigInt("00010000000000000000000000000000", 16), Some(80)),
"[2001:DB8:85A3:8D3:1319:8A2E:370:7348]:443" -> ResultContainer(6, BigInt("20010db885a308d313198a2e03707348", 16), Some(443), strictRFC5952 = false),
"[2605:2700:0:3::4713:93E3]:80" -> ResultContainer(6, BigInt("260527000000000300000000471393e3", 16), Some(80), strictRFC5952 = false),
"[::1]:80" -> ResultContainer(6, BigInt("00000000000000000000000000000001", 16), Some(80)),
"[::1]:65536" ->
IPInvalidAddressComponents(6, BigInt("00000000000000000000000000000001", 16), Some(65536), remark = "Port number out of range."),
"[::]:80" -> ResultContainer(6, BigInt("00000000000000000000000000000000", 16), Some(80)),
"[::FFFF:192.168.0.1]:22" -> ResultContainer(6, BigInt("00000000000000000000ffffc0a80001", 16), Some(22), strictRFC5952 = false),
"[::FFFF:192.168.173.22]:80" -> ResultContainer(6, BigInt("00000000000000000000ffffc0a8ad16", 16), Some(80), strictRFC5952 = false),
"[::FFFF:71.19.147.227]:80" -> ResultContainer(6, BigInt("00000000000000000000ffff471393e3", 16), Some(80), strictRFC5952 = false),
"A::B::1" -> IPInvalidAddressComponents(remark = "Noise found: 'A::B::1'."),
"FFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF" -> ResultContainer(6, BigInt("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16), strictRFC5952 = false),
"FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF" -> ResultContainer(6, BigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16), strictRFC5952 = false),
"FFFF:FFFF:FFFF:FFFG:FFFF:FFFF:FFFF:FFFF" -> IPInvalidAddressComponents(remark = "No match at all: 'FFFF:FFFF:FFFF:FFFG…'."),
"G::1" -> IPInvalidAddressComponents(6, remark = "Invalid input 'G::1'."),
"64:FF9B::192.0.2.33" -> ResultContainer(6, BigInt("0064FF9B0000000000000000C0000221", 16), strictRFC5952 = false),
"64:FF9B::256.0.2.33" -> IPInvalidAddressComponents(6, BigInt("0064FF9B000000000000000000000000", 16), remark = "Invalid octets.")
)

def IPInvalidAddressComponents(version: Int = 0,
address: BigInt = BigInt(0),
port: Option[Int] = None,
valid: Boolean = false,
remark: String = "",
strict: Boolean = false) = ResultContainer(version, address, port, valid, remark, strict)

case class ResultContainer(version: Int,
address: BigInt,
port: Option[Int] = None,
valid: Boolean = true,
remark: String = "",
strictRFC5952: Boolean = true)

class IpAddress(val originalString: String) {

import IpAddress._

val (usedPattern, result: ResultContainer) = originalString match {
case trapPattern() => (trapPattern, IPInvalidAddressComponents(remark = s"Noise found: '${shortener(originalString)}'."))
case allIpV6PortedPatternsCompiled(adr, port) => parseIpV6(adr, Option(port).map(_.toInt))
case allIpV6UnspecPortPatternsCompiled(adr) => parseIpV6(adr)
case ipV4PortSpecCompiled(adr, port) => (ipV4PortSpecCompiled, parseIpV4(adr, Option(port).map(_.toInt)))
case _ => ("Exhausted of all matches.", IPInvalidAddressComponents(remark = s"No match at all: '${shortener(originalString, 19)}'."))
}

override def toString: String = {
def hexAddr = if (result.version == 6) f"${result.address}%#034x" else f"${result.address}%#010x"

def validInd = if (result.valid) '\u2714' else '\u2718'

def rfc5952 = if (result.strictRFC5952) "comply" else "broken"

def version = result.version match {
case 0 => " ?"
case 4 => "IPv4"
case 6 => "IPv6"
}

def surround(s: String) = if (result.valid) s" $s " else s"($s)"

def port = if (result.port.isDefined) surround(result.port.get.toString) else if (result.valid) " " else "? "

def hexAddrField = f"${if (result.valid || result.address != 0) surround(hexAddr) else "? "}%36s "

f"${shortener(originalString, 45)}%46s $version $validInd $rfc5952 $hexAddrField $port%8s ${result.remark}%-40s $usedPattern"
}

def shortener(s: String, maxlength: Int = 12): String = {
val size = s.length()
s.substring(0, math.min(size, maxlength)) + (if (size > maxlength) "…" else "")
}

private def parseIpV6(ipAddress: String, port: Option[Int] = None): (String, ResultContainer) = {

def colonedStringToBigInt(colonedString: String): (BigInt, Int) = {
// Compressed zeroes expansion
val ar = if (colonedString contains "::") colonedString.split("::", 2) else Array("", colonedString)
val (left, right) = (ar.head.split(':').filterNot(_.isEmpty), ar(1).split(':').filterNot(_.isEmpty))
val sixteenBitExpansions = 8 - (right.length + left.length)

((left ++ Seq.fill(sixteenBitExpansions)("0") ++ right)
.map(BigInt(_, 16).toLong).map(BigInt(_)).reduceLeft((acc, i) => (acc << 16) | i),
sixteenBitExpansions)
}

def parseEmbeddedV4(seg: String, ip4Seg: String, usedRegEx: String): (String, ResultContainer) = {
val (ip4, ip6Parser, test) =
(parseIpV4(ip4Seg), colonedStringToBigInt(seg.replaceFirst(ipV4Regex("3"), "0:0")), portNumberTest(port))

(usedRegEx, ResultContainer(originalString, 6, ip4.address + ip6Parser._1, port,
ip4.valid && test.isEmpty, ip4.remark + test, ip4.valid && test.isEmpty))
}

if (!ipAddress.forall((('A' to 'F') ++ ('a' to 'f') ++ ('0' to '9') ++ Vector(':', '.')).contains(_)))
("[^:.[0-9][A-F][a-f]]", IPInvalidAddressComponents(6, remark = s"Invalid input '${shortener(ipAddress)}'."))
else
ipAddress match {
case pattern10Compiled(seg, ip4Seg) => parseEmbeddedV4(seg, ip4Seg, pattern10Compiled.toString())
case pattern11Compiled(seg, ip4Seg) => parseEmbeddedV4(seg, ip4Seg, pattern11Compiled.toString())
case ip6PatternsRawCompiled(seg, _*) =>
val (ip6Parser, test) = (colonedStringToBigInt(seg), portNumberTest(port))

(ip6PatternsRawCompiled.toString(),
ResultContainer(ipAddress, 6, ip6Parser._1, port,
valid = test.isEmpty, test, strictRFC5952 = ip6Parser._2 != 1 && test.isEmpty))
case _ => ("V6 match exhausted.", IPInvalidAddressComponents(6, remark = "V6 address puntation error."))
}
} // parseIpV6


private def parseIpV4(sIP: String, port: Option[Int] = None): ResultContainer = {

def wordsToNum(words: Array[Long]): Long = words.reduceLeft((acc, i) => (acc << 8) | i)

if (sIP.head.isDigit && sIP.matches(ipV4Regex("3"))) {
val octets = sIP.split('.').map(_.toLong)
if (octets.forall(_ < 256)) {
val portNumberOK = portNumberTest(port)
ResultContainer(4, BigInt(wordsToNum(octets)), port, portNumberOK.isEmpty, portNumberOK, portNumberOK.isEmpty)
} else IPInvalidAddressComponents(4, remark = "Invalid octets.")
}
else IPInvalidAddressComponents(4, remark = s"Address puntation error: '${shortener(sIP)}'.")
}

private def portNumberTest(port: Option[Int]) = if (port.isEmpty || port.get < math.pow(2, 16)) "" else "Port number out of range."
} // IpAddress

object IpAddress {
val (ip6PatternsRawCompiled, pattern11Compiled) = (ipV6Patterns.mkString("(", "|", ")").r, embeddedV4patterns()(1).r)
val (trapPattern, pattern10Compiled) = (""".*?(?:(?:\w*:{2,}?){2,}?\w)|(?:\[?)""".r, embeddedV4patterns().head.r)
val allIpV6PortedPatternsCompiled = ("""[^\\.]*?\[(""" + allIpV6 +""")\](?::(\d{1,6}))?[^\.:]*?""").r
val allIpV6UnspecPortPatternsCompiled = (""".*?(""" + allIpV6 +""")[^\.:]*?""").r
val ipV4PortSpecCompiled = s".*?([:.\\]]?${ipV4Regex()})(?::(\\d{1,6}))?.*?".r

// Make a regex pattern with non-capturing groups by the disabling the capturing group syntax (?:).
def allIpV6 = (embeddedV4patterns("(?:") ++ ipV6Patterns).map(s => "(?:" + s.drop(1)).mkString("|")

def ipV6Patterns = {
def ipV6SegRegWC = """\w{1,4}"""

Seq(
s"((?::(?:(?::$ipV6SegRegex){1,7}|:)))",
s"((?:$ipV6SegRegWC:(?::$ipV6SegRegex){1,6}))",
s"((?:$ipV6SegRegex:){1,2}(?::$ipV6SegRegex){1,5})",
s"((?:$ipV6SegRegex:){1,3}(?::$ipV6SegRegex){1,4})",
s"((?:$ipV6SegRegex:){1,4}(?::$ipV6SegRegex){1,3})",
s"((?:$ipV6SegRegex:){1,5}(?::$ipV6SegRegex){1,2})",
s"((?:$ipV6SegRegex:){1,6}:$ipV6SegRegex)",
s"((?:$ipV6SegRegex:){1,7}:)",
s"((?:$ipV6SegRegex:){7}$ipV6SegRegex)"
)
}

private def embeddedV4patterns(nonCapturePrefix: String = "(") =
Seq(s"(::(?:(?:FFFF|ffff)(?::0{1,4}){0,1}:){0,1}$nonCapturePrefix${ipV4Regex("3")}))",
s"((?:$ipV6SegRegex:){1,4}:$nonCapturePrefix${ipV4Regex("3")}))")

private def ipV6SegRegex = """[\dA-Fa-f]{1,4}"""

private def ipV4Regex(octets: String = "3,") = s"(?:\\d{1,3}\\.){$octets}\\d{1,3}"
}

object ResultContainer {
def apply(orginalString: String, version: Int,
address: BigInt, port: Option[Int],
valid: Boolean, remark: String,
strictRFC5952: Boolean): ResultContainer =
// To comply with strictRFC5952 all alpha character must be lowercase too.
this (version, address, port, valid, remark, strictRFC5952 && !orginalString.exists(_.isUpper))
}

{
val headline = Seq(f"${"IP addresses to be parsed. "}%46s", "Ver.", f"${"S"}%1s", "RFC5952",
f"${"Hexadecimal IP address"}%34s", f"${"Port "}%10s", f"${" Remark"}%-40s", f"${" Effective RegEx"}%-40s")

println(headline.mkString("|") + "\n" + headline.map(s => "-" * s.length).mkString("+"))

val cases: Set[IpAddress] = myCases.keySet.map(new IpAddress(_))

println(cases.toList.sortBy(s => (s.originalString.length, s.originalString)).mkString("\n"))
logInfo(s"Concluding: ${myCases.size} cases processed, ${cases.count(_.result.valid)} valid ✔ and ${cases.count(!_.result.valid)} invalid ✘.")
logInfo("Successfully completed without errors.")

def logInfo(info: String) {
println(f"[Info][${System.currentTimeMillis() - executionStart}%5d ms]" + info)
}
}


} // IPparser cloc.exe : 235 loc</syntaxhighlight>
With [[BSD]], ''fe80::1%lo0'' is a link-local address. With other systems, ''fe80::1%lo0'' might be illegal address, because ''lo0'' is not valid scope identifier.


=={{header|Tcl}}==
=={{header|Tcl}}==
{{tcllib|ip}}
{{tcllib|ip}}
<lang tcl>package require Tcl 8.5
<syntaxhighlight lang="tcl">package require Tcl 8.5
package require ip
package require ip


Line 2,176: Line 3,897:
set port -1
set port -1
if {$family == -1} {
if {$family == -1} {
if {[regexp {^\[(.*)\]:(\d+)$} $address -> address port]} {
if {[regexp {^\[(.*)\]:(\d+)$} $address -> address port]} {
dict set result port $port
dict set result port $port
set family [ip::version $address]
set family [ip::version $address]
if {$family != 6} {
if {$family != 6} {
return -code error "bad address"
return -code error "bad address"
}
}
} elseif {[regexp {^(.*):(\d+)$} $address -> address port]} {
} elseif {[regexp {^(.*):(\d+)$} $address -> address port]} {
dict set result port $port
dict set result port $port
set family [ip::version $address]
set family [ip::version $address]
if {$family != 4} {
if {$family != 4} {
return -code error "bad address"
return -code error "bad address"
}
}
} else {
} else {
return -code error "bad address"
return -code error "bad address"
}
}
}
}
# Only possible error in ports is to be too large an integer
# Only possible error in ports is to be too large an integer
if {$port > 65535} {
if {$port > 65535} {
return -code error "bad port"
return -code error "bad port"
}
}
dict set result family $family
dict set result family $family
if {$family == 4} {
if {$family == 4} {
# IPv4 normalized form is dotted quad, but toInteger helps
# IPv4 normalized form is dotted quad, but toInteger helps
dict set result addr [format %x [ip::toInteger $address]]
dict set result addr [format %x [ip::toInteger $address]]
} else {
} else {
# IPv6 normalized form is colin-separated hex
# IPv6 normalized form is colin-separated hex
dict set result addr [string map {: ""} [ip::normalize $address]]
dict set result addr [string map {: ""} [ip::normalize $address]]
}
}
# Return the descriptor dictionary
# Return the descriptor dictionary
return $result
return $result
}</lang>
}</syntaxhighlight>
Demonstration code:
Demonstration code:
<lang tcl>foreach address {
<syntaxhighlight lang="tcl">foreach address {
127.0.0.1
127.0.0.1
127.0.0.1:80
127.0.0.1:80
Line 2,222: Line 3,943:
} {
} {
if {[catch {
if {[catch {
set parsed [parseIP $address]
set parsed [parseIP $address]
} msg]} {
} msg]} {
puts "error ${msg}: \"$address\""
puts "error ${msg}: \"$address\""
continue
continue
}
}
dict with parsed {
dict with parsed {
puts -nonewline "family: IPv$family addr: $addr"
puts -nonewline "family: IPv$family addr: $addr"
if {[dict exists $parsed port]} {
if {[dict exists $parsed port]} {
puts -nonewline " port: $port"
puts -nonewline " port: $port"
}
}
puts ""
puts ""
}
}
}</lang>
}</syntaxhighlight>
Output:
Output:
<pre>
<pre>
Line 2,251: Line 3,972:


=={{header|VBScript}}==
=={{header|VBScript}}==
<lang vb>Function parse_ip(addr)
<syntaxhighlight lang="vb">Function parse_ip(addr)
'ipv4 pattern
'ipv4 pattern
Set ipv4_pattern = New RegExp
Set ipv4_pattern = New RegExp
ipv4_pattern.Global = True
ipv4_pattern.Global = True
ipv4_pattern.Pattern = "(\d{1,3}\.){3}\d{1,3}"
ipv4_pattern.Pattern = "(\d{1,3}\.){3}\d{1,3}"
'ipv6 pattern
'ipv6 pattern
Set ipv6_pattern = New RegExp
Set ipv6_pattern = New RegExp
ipv6_pattern.Global = True
ipv6_pattern.Global = True
ipv6_pattern.Pattern = "([0-9a-fA-F]{0,4}:){2}[0-9a-fA-F]{0,4}"
ipv6_pattern.Pattern = "([0-9a-fA-F]{0,4}:){2}[0-9a-fA-F]{0,4}"
'test if address is ipv4
'test if address is ipv4
If ipv4_pattern.Test(addr) Then
If ipv4_pattern.Test(addr) Then
port = Split(addr,":")
port = Split(addr,":")
octet = Split(port(0),".")
octet = Split(port(0),".")
ipv4_hex = ""
ipv4_hex = ""
For i = 0 To UBound(octet)
For i = 0 To UBound(octet)
If octet(i) <= 255 And octet(i) >= 0 Then
If octet(i) <= 255 And octet(i) >= 0 Then
ipv4_hex = ipv4_hex & Right("0" & Hex(octet(i)),2)
ipv4_hex = ipv4_hex & Right("0" & Hex(octet(i)),2)
Else
Else
ipv4_hex = "Erroneous Address"
ipv4_hex = "Erroneous Address"
Exit For
Exit For
End If
End If
Next
Next
parse_ip = "Test Case: " & addr & vbCrLf &_
parse_ip = "Test Case: " & addr & vbCrLf &_
"Address: " & ipv4_hex & vbCrLf
"Address: " & ipv4_hex & vbCrLf
If UBound(port) = 1 Then
If UBound(port) = 1 Then
If port(1) <= 65535 And port(1) >= 0 Then
If port(1) <= 65535 And port(1) >= 0 Then
parse_ip = parse_ip & "Port: " & port(1) & vbCrLf
parse_ip = parse_ip & "Port: " & port(1) & vbCrLf
Else
Else
parse_ip = parse_ip & "Port: Invalid" & vbCrLf
parse_ip = parse_ip & "Port: Invalid" & vbCrLf
End If
End If
End If
End If
End If
End If
'test if address is ipv6
'test if address is ipv6
If ipv6_pattern.Test(addr) Then
If ipv6_pattern.Test(addr) Then
parse_ip = "Test Case: " & addr & vbCrLf
parse_ip = "Test Case: " & addr & vbCrLf
port_v6 = "Port: "
port_v6 = "Port: "
ipv6_hex = ""
ipv6_hex = ""
'check and extract port information if any
'check and extract port information if any
If InStr(1,addr,"[") Then
If InStr(1,addr,"[") Then
'extract the port
'extract the port
port_v6 = port_v6 & Mid(addr,InStrRev(addr,"]")+2,Len(addr)-Len(Mid(addr,1,InStrRev(addr,"]")+1)))
port_v6 = port_v6 & Mid(addr,InStrRev(addr,"]")+2,Len(addr)-Len(Mid(addr,1,InStrRev(addr,"]")+1)))
'extract the address
'extract the address
addr = Mid(addr,InStrRev(addr,"[")+1,InStrRev(addr,"]")-(InStrRev(addr,"[")+1))
addr = Mid(addr,InStrRev(addr,"[")+1,InStrRev(addr,"]")-(InStrRev(addr,"[")+1))
End If
End If
word = Split(addr,":")
word = Split(addr,":")
word_count = 0
word_count = 0
For i = 0 To UBound(word)
For i = 0 To UBound(word)
If word(i) = "" Then
If word(i) = "" Then
If i < UBound(word) Then
If i < UBound(word) Then
If Int((7-(i+1))/2) = 1 Then
If Int((7-(i+1))/2) = 1 Then
k = 1
k = 1
ElseIf UBound(word) < 6 Then
ElseIf UBound(word) < 6 Then
k = Int((7-(i+1))/2)
k = Int((7-(i+1))/2)
ElseIf UBound(word) >= 6 Then
ElseIf UBound(word) >= 6 Then
k = Int((7-(i+1))/2)-1
k = Int((7-(i+1))/2)-1
End If
End If
For j = 0 To k
For j = 0 To k
ipv6_hex = ipv6_hex & "0000"
ipv6_hex = ipv6_hex & "0000"
word_count = word_count + 1
word_count = word_count + 1
Next
Next
Else
Else
For j = 0 To (7-word_count)
For j = 0 To (7-word_count)
ipv6_hex = ipv6_hex & "0000"
ipv6_hex = ipv6_hex & "0000"
Next
Next
End If
End If
Else
Else
ipv6_hex = ipv6_hex & Right("0000" & word(i),4)
ipv6_hex = ipv6_hex & Right("0000" & word(i),4)
word_count = word_count + 1
word_count = word_count + 1
End If
End If
Next
Next
parse_ip = parse_ip & "Address: " & ipv6_hex &_
parse_ip = parse_ip & "Address: " & ipv6_hex &_
vbCrLf & port_v6 & vbCrLf
vbCrLf & port_v6 & vbCrLf
End If
End If
'test if the address in invalid
'test if the address in invalid
If ipv4_pattern.Test(addr) = False And ipv6_pattern.Test(addr) = False Then
If ipv4_pattern.Test(addr) = False And ipv6_pattern.Test(addr) = False Then
parse_ip = "Test Case: " & addr & vbCrLf &_
parse_ip = "Test Case: " & addr & vbCrLf &_
"Address: Invalid Address" & vbCrLf
"Address: Invalid Address" & vbCrLf
End If
End If
End Function
End Function


'Testing the function
'Testing the function
ip_arr = Array("127.0.0.1","127.0.0.1:80","::1",_
ip_arr = Array("127.0.0.1","127.0.0.1:80","::1",_
"[::1]:80","2605:2700:0:3::4713:93e3","[2605:2700:0:3::4713:93e3]:80","RosettaCode")
"[::1]:80","2605:2700:0:3::4713:93e3","[2605:2700:0:3::4713:93e3]:80","RosettaCode")


For n = 0 To UBound(ip_arr)
For n = 0 To UBound(ip_arr)
WScript.StdOut.Write parse_ip(ip_arr(n)) & vbCrLf
WScript.StdOut.Write parse_ip(ip_arr(n)) & vbCrLf
Next</lang>
Next</syntaxhighlight>


{{Out}}
{{Out}}
Line 2,366: Line 4,087:
Test Case: RosettaCode
Test Case: RosettaCode
Address: Invalid Address
Address: Invalid Address
</pre>

=={{header|V (Vlang)}}==
{{trans|AutoHotkey}}
<syntaxhighlight lang="v (vlang)">const data =
('
127.0.0.1
127.0.0.1:80
::1
[::1]:80
2605:2700:0:3::4713:93e3
[2605:2700:0:3::4713:93e3]:80
')

fn main() {
mut output :=''
for val in data.split('\n') {
if val !='' {
xarr := parse_ip(val)
output += 'input = ' + val + '\t>\t' + xarr[0] + if xarr[1] !='' {' port : ' + xarr[1]} else {''} + '\n'
}
}
println(output)
}

fn parse_ip(address string) []string {
return if address.contains('.') {ipv4(address)} else {ipv6(address)}
}

fn ipv4(address string) []string {
mut num, mut port := '', ''
for val in address.split('.') {
xarr := val.split(':')
num += xarr[0].int().hex2().replace('x','')
if xarr.len > 1 {port = xarr[1]} else {port =''}
}
return [num, port]
}

fn ipv6(address string) []string {
mut num, mut port := '', ''
for idx, val in address.split(']') {
if idx == 0 {
for xal in val.trim_left('[:').split(':') {
if xal =='' {num += '00000000'} else {num += '0000'.substr(0, 4 - xal.len) + xal}
}
}
else {port = val.trim_left(':')}
}
return ['00000000000000000000000000000000'.substr(0, 32 - num.len) + num, port]
}</syntaxhighlight>

{{out}}
<pre>
input = 127.0.0.1 > 07f000001
input = 127.0.0.1:80 > 07f000001 port : 80
input = ::1 > 00000000000000000000000000000001
input = [::1]:80 > 00000000000000000000000000000001 port : 80
input = 2605:2700:0:3::4713:93e3 > 260527000000000300000000471393e3
input = [2605:2700:0:3::4713:93e3]:80 > 260527000000000300000000471393e3 port : 80
</pre>

=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-dynamic}}
{{libheader|wren-big}}
{{libheader|Wren-str}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./dynamic" for Enum, Tuple
import "./big" for BigInt
import "./str" for Str
import "./fmt" for Conv, Fmt

var AddressSpace = Enum.create("AddressSpace", ["IPv4", "IPv6", "Invalid"])

// a port of -1 denotes 'not specified'
var IPAddressComponents = Tuple.create("IPAddressComponents", ["address", "addressSpace", "port"])

var INVALID = IPAddressComponents.new(BigInt.zero, AddressSpace.Invalid, 0)

var ipAddressParse = Fn.new { |ipAddress|
var addressSpace = AddressSpace.IPv4
var ipa = Str.lower(ipAddress)
var port = -1
var trans = false

if (ipa.startsWith("::ffff:") && ipa.contains(".")) {
addressSpace = AddressSpace.IPv6
trans = true
ipa = ipa[7..-1]
} else if (ipa.startsWith("[::ffff:") && ipa.contains(".")) {
addressSpace = AddressSpace.IPv6
trans = true
ipa = ipa[8..-1].replace("]", "")
}
var octets = ipa.split(".")[-1..0].toList
var address = BigInt.zero
if (octets.count == 4) {
var split = octets[0].split(":")
if (split.count == 2) {
var temp = Num.fromString(split[1])
if (!temp || temp < 0 || temp > 65535) return INVALID
port = temp
octets[0] = split[0]
}
for (i in 0..3) {
var num = Num.fromString(octets[i])
if (!num || num < 0 || num > 255) return INVALID
var bigNum = BigInt.new(num)
address = address | (bigNum << (i * 8))
}
if (trans) address = address + BigInt.fromBaseString("ffff00000000", 16)
} else if (octets.count == 1) {
addressSpace = AddressSpace.IPv6
if (ipa[0] == "[") {
ipa = ipa[1..-1]
var split = ipa.split("]:")
if (split.count != 2) return INVALID
var temp = Num.fromString(split[1])
if (!temp || temp < 0 || temp > 65535) return INVALID
port = temp
ipa = ipa[0...(-2 - split[1].count)]
}
var hextets = ipa.split(":")[-1..0].toList
var len = hextets.count

if (ipa.startsWith("::")) {
hextets[-1] = "0"
} else if (ipa.endsWith("::")) {
hextets[0] = "0"
}
if (ipa == "::") hextets[1] = "0"
if (len > 8 || (len == 8 && hextets.any { |h| h == "" }) || hextets.count { |h| h == "" } > 1) {
return INVALID
}
if (len < 8) {
var insertions = 8 - len
for (i in 0..7) {
if (hextets[i] == "") {
hextets[i] = "0"
while (insertions > 0) {
insertions = insertions - 1
hextets.insert(i, "0")
}
break
}
}
}
for (j in 0..7) {
var num = Conv.atoi(hextets[j], 16)
if (num > 0xFFFF) return INVALID
var bigNum = BigInt.new(num)
address = address | (bigNum << (j * 16))
}
} else return INVALID

return IPAddressComponents.new(address, addressSpace, port)
}

var ipas = [
"127.0.0.1",
"127.0.0.1:80",
"::1",
"[::1]:80",
"2605:2700:0:3::4713:93e3",
"[2605:2700:0:3::4713:93e3]:80",
"::ffff:192.168.173.22",
"[::ffff:192.168.173.22]:80",
"1::",
"::",
"256.0.0.0",
"::ffff:127.0.0.0.1"
]
for (ipa in ipas) {
var ipac = ipAddressParse.call(ipa)
Fmt.print("IP address : $s", ipa)
Fmt.print("Address : $s", Str.upper(ipac.address.toBaseString(16)))
Fmt.print("Address Space : $s", AddressSpace.members[ipac.addressSpace])
Fmt.print("Port : $s", (ipac.port == -1) ? "not specified" : ipac.port.toString)
System.print()
}</syntaxhighlight>

{{out}}
<pre>
IP address : 127.0.0.1
Address : 7F000001
Address Space : IPv4
Port : not specified

IP address : 127.0.0.1:80
Address : 7F000001
Address Space : IPv4
Port : 80

IP address : ::1
Address : 1
Address Space : IPv6
Port : not specified

IP address : [::1]:80
Address : 1
Address Space : IPv6
Port : 80

IP address : 2605:2700:0:3::4713:93e3
Address : 260527000000000300000000471393E3
Address Space : IPv6
Port : not specified

IP address : [2605:2700:0:3::4713:93e3]:80
Address : 260527000000000300000000471393E3
Address Space : IPv6
Port : 80

IP address : ::ffff:192.168.173.22
Address : FFFFC0A8AD16
Address Space : IPv6
Port : not specified

IP address : [::ffff:192.168.173.22]:80
Address : FFFFC0A8AD16
Address Space : IPv6
Port : 80

IP address : 1::
Address : 10000000000000000000000000000
Address Space : IPv6
Port : not specified

IP address : ::
Address : 0
Address Space : IPv6
Port : not specified

IP address : 256.0.0.0
Address : 0
Address Space : Invalid
Port : 0

IP address : ::ffff:127.0.0.0.1
Address : 0
Address Space : Invalid
Port : 0
</pre>
</pre>

Latest revision as of 08:48, 5 March 2024

Task
Parse an IP Address
You are encouraged to solve this task according to the task description, using any language you may know.

The purpose of this task is to demonstrate parsing of text-format IP addresses, using IPv4 and IPv6.


Taking the following as inputs:

127.0.0.1 The "localhost" IPv4 address
127.0.0.1:80 The "localhost" IPv4 address, with a specified port (80)
::1 The "localhost" IPv6 address
[::1]:80 The "localhost" IPv6 address, with a specified port (80)
2605:2700:0:3::4713:93e3 Rosetta Code's primary server's public IPv6 address
[2605:2700:0:3::4713:93e3]:80 Rosetta Code's primary server's public IPv6 address, with a specified port (80)


Task

Emit each described IP address as a hexadecimal integer representing the address, the address space, and the port number specified, if any.

In languages where variant result types are clumsy, the result should be ipv4 or ipv6 address number, something which says which address space was represented, port number and something that says if the port was specified.


Example

127.0.0.1   has the address number   7F000001   (2130706433 decimal) in the ipv4 address space.

::ffff:127.0.0.1   represents the same address in the ipv6 address space where it has the address number   FFFF7F000001   (281472812449793 decimal).

::1   has address number   1   and serves the same purpose in the ipv6 address space that   127.0.0.1   serves in the ipv4 address space.

AutoHotkey

ParseIP(Address){
	return InStr(A_LoopField, ".") ? IPv4(Address) : IPv6(Address)
}

IPv4(Address){
	for i, v in StrSplit(Address, "."){
		x := StrSplit(v, ":")
		num .= SubStr("00" . Format("{:X}", x.1), -1) 
		port := x.2 ? x.2 : ""
	}
	return [num, port]
}

IPv6(Address){
	for i, v in StrSplit(Address, "]")
		if i = 1
			for j, x in StrSplit(LTrim(v, "[:"), ":")
				num .= x = "" ? "00000000" : SubStr("0000" x, -3)
		else
			port := LTrim(v, ":")
	return [SubStr("00000000000000000000000000000000" num, -31), port]
}

Examples:

data =
(
127.0.0.1
127.0.0.1:80
::1
[::1]:80
2605:2700:0:3::4713:93e3
[2605:2700:0:3::4713:93e3]:80
)

output := ""
loop, parse, data, `n, `r
{
	x := ParseIP(A_LoopField)
	output .= "input = " A_LoopField "`t>`t" x.1 . (x.2 ? " port : " x.2 : "") "`n"
}
MsgBox % output
return
Output:

input = 127.0.0.1 > 7F000001 input = 127.0.0.1:80 > 7F000001 port : 80 input = ::1 > 00000000000000000000000000000001 input = [::1]:80 > 00000000000000000000000000000001 port : 80 input = 2605:2700:0:3::4713:93e3 > 260527000000000300000000471393e3 input = [2605:2700:0:3::4713:93e3]:80 > 260527000000000300000000471393e3 port : 80

C

#include <string.h>
#include <memory.h>


static unsigned int _parseDecimal ( const char** pchCursor )
{
    unsigned int nVal = 0;
    char chNow;
    while ( chNow = **pchCursor, chNow >= '0' && chNow <= '9' )
    {
        //shift digit in
        nVal *= 10;
        nVal += chNow - '0';

        ++*pchCursor;
    }
    return nVal;
}



static unsigned int _parseHex ( const char** pchCursor )
{
    unsigned int nVal = 0;
    char chNow;
    while ( chNow = **pchCursor & 0x5f, //(collapses case, but mutilates digits)
            (chNow >= ('0'&0x5f) && chNow <= ('9'&0x5f)) || 
            (chNow >= 'A' && chNow <= 'F') 
            )
    {
        unsigned char nybbleValue;
        chNow -= 0x10;  //scootch digital values down; hex now offset by x31
        nybbleValue = ( chNow > 9 ? chNow - (0x31-0x0a) : chNow );
        //shift nybble in
        nVal <<= 4;
        nVal += nybbleValue;

        ++*pchCursor;
    }
    return nVal;
}



//Parse a textual IPv4 or IPv6 address, optionally with port, into a binary
//array (for the address, in network order), and an optionally provided port.
//Also, indicate which of those forms (4 or 6) was parsed.  Return true on
//success.  ppszText must be a nul-terminated ASCII string.  It will be
//updated to point to the character which terminated parsing (so you can carry
//on with other things.  abyAddr must be 16 bytes.  You can provide NULL for
//abyAddr, nPort, bIsIPv6, if you are not interested in any of those
//informations.  If we request port, but there is no port part, then nPort will
//be set to 0.  There may be no whitespace leading or internal (though this may
//be used to terminate a successful parse.
//Note:  the binary address and integer port are in network order.
int ParseIPv4OrIPv6 ( const char** ppszText, 
        unsigned char* abyAddr, int* pnPort, int* pbIsIPv6 )
{
    unsigned char* abyAddrLocal;
    unsigned char abyDummyAddr[16];

    //find first colon, dot, and open bracket
    const char* pchColon = strchr ( *ppszText, ':' );
    const char* pchDot = strchr ( *ppszText, '.' );
    const char* pchOpenBracket = strchr ( *ppszText, '[' );
    const char* pchCloseBracket = NULL;


    //we'll consider this to (probably) be IPv6 if we find an open
    //bracket, or an absence of dots, or if there is a colon, and it
    //precedes any dots that may or may not be there
    int bIsIPv6local = NULL != pchOpenBracket || NULL == pchDot ||
            ( NULL != pchColon && ( NULL == pchDot || pchColon < pchDot ) );
    //OK, now do a little further sanity check our initial guess...
    if ( bIsIPv6local )
    {
        //if open bracket, then must have close bracket that follows somewhere
        pchCloseBracket = strchr ( *ppszText, ']' );
        if ( NULL != pchOpenBracket && ( NULL == pchCloseBracket ||
                pchCloseBracket < pchOpenBracket ) )
            return 0;
    }
    else    //probably ipv4
    {
        //dots must exist, and precede any colons
        if ( NULL == pchDot || ( NULL != pchColon && pchColon < pchDot ) )
            return 0;
    }

    //we figured out this much so far....
    if ( NULL != pbIsIPv6 )
        *pbIsIPv6 = bIsIPv6local;
    
    //especially for IPv6 (where we will be decompressing and validating)
    //we really need to have a working buffer even if the caller didn't
    //care about the results.
    abyAddrLocal = abyAddr; //prefer to use the caller's
    if ( NULL == abyAddrLocal ) //but use a dummy if we must
        abyAddrLocal = abyDummyAddr;

    //OK, there should be no correctly formed strings which are miscategorized,
    //and now any format errors will be found out as we continue parsing
    //according to plan.
    if ( ! bIsIPv6local )   //try to parse as IPv4
    {
        //4 dotted quad decimal; optional port if there is a colon
        //since there are just 4, and because the last one can be terminated
        //differently, I'm just going to unroll any potential loop.
        unsigned char* pbyAddrCursor = abyAddrLocal;
        unsigned int nVal;
        const char* pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           //get first val
        if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )    //must be in range and followed by dot and nonempty
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;  //stick it in addr
        ++(*ppszText);  //past the dot

        pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           //get second val
        if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;
        ++(*ppszText);  //past the dot

        pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           //get third val
        if ( '.' != **ppszText || nVal > 255 || pszTextBefore == *ppszText )
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;
        ++(*ppszText);  //past the dot

        pszTextBefore = *ppszText;
        nVal =_parseDecimal ( ppszText );           //get fourth val
        if ( nVal > 255 || pszTextBefore == *ppszText ) //(we can terminate this one in several ways)
            return 0;
        *(pbyAddrCursor++) = (unsigned char) nVal;

        if ( ':' == **ppszText && NULL != pnPort )  //have port part, and we want it
        {
            unsigned short usPortNetwork;   //save value in network order
            ++(*ppszText);  //past the colon
            pszTextBefore = *ppszText;
            nVal =_parseDecimal ( ppszText );
            if ( nVal > 65535 || pszTextBefore == *ppszText )
                return 0;
            ((unsigned char*)&usPortNetwork)[0] = ( nVal & 0xff00 ) >> 8;
            ((unsigned char*)&usPortNetwork)[1] = ( nVal & 0xff );
            *pnPort = usPortNetwork;
            return 1;
        }
        else    //finished just with ip address
        {
            if ( NULL != pnPort )
                *pnPort = 0;    //indicate we have no port part
            return 1;
        }
    }
    else    //try to parse as IPv6
    {
        unsigned char* pbyAddrCursor;
        unsigned char* pbyZerosLoc;
        int bIPv4Detected;
        int nIdx;
        //up to 8 16-bit hex quantities, separated by colons, with at most one
        //empty quantity, acting as a stretchy run of zeroes.  optional port
        //if there are brackets followed by colon and decimal port number.
        //A further form allows an ipv4 dotted quad instead of the last two
        //16-bit quantities, but only if in the ipv4 space ::ffff:x:x .
        if ( NULL != pchOpenBracket )   //start past the open bracket, if it exists
            *ppszText = pchOpenBracket + 1;
        pbyAddrCursor = abyAddrLocal;
        pbyZerosLoc = NULL; //if we find a 'zero compression' location
        bIPv4Detected = 0;
        for ( nIdx = 0; nIdx < 8; ++nIdx )  //we've got up to 8 of these, so we will use a loop
        {
            const char* pszTextBefore = *ppszText;
            unsigned nVal =_parseHex ( ppszText );      //get value; these are hex
            if ( pszTextBefore == *ppszText )   //if empty, we are zero compressing; note the loc
            {
                if ( NULL != pbyZerosLoc )  //there can be only one!
                {
                    //unless it's a terminal empty field, then this is OK, it just means we're done with the host part
                    if ( pbyZerosLoc == pbyAddrCursor )
                    {
                        --nIdx;
                        break;
                    }
                    return 0;   //otherwise, it's a format error
                }
                if ( ':' != **ppszText )    //empty field can only be via :
                    return 0;
                if ( 0 == nIdx )    //leading zero compression requires an extra peek, and adjustment
                {
                    ++(*ppszText);
                    if ( ':' != **ppszText )
                        return 0;
                }

                pbyZerosLoc = pbyAddrCursor;
                ++(*ppszText);
            }
            else
            {
                if ( '.' == **ppszText )    //special case of ipv4 convenience notation
                {
                    //who knows how to parse ipv4?  we do!
                    const char* pszTextlocal = pszTextBefore;   //back it up
                    unsigned char abyAddrlocal[16];
                    int bIsIPv6local;
                    int bParseResultlocal = ParseIPv4OrIPv6 ( &pszTextlocal, abyAddrlocal, NULL, &bIsIPv6local );
                    *ppszText = pszTextlocal;   //success or fail, remember the terminating char
                    if ( ! bParseResultlocal || bIsIPv6local )  //must parse and must be ipv4
                        return 0;
                    //transfer addrlocal into the present location
                    *(pbyAddrCursor++) = abyAddrlocal[0];
                    *(pbyAddrCursor++) = abyAddrlocal[1];
                    *(pbyAddrCursor++) = abyAddrlocal[2];
                    *(pbyAddrCursor++) = abyAddrlocal[3];
                    ++nIdx; //pretend like we took another short, since the ipv4 effectively is two shorts
                    bIPv4Detected = 1;  //remember how we got here for further validation later
                    break;  //totally done with address
                }

                if ( nVal > 65535 ) //must be 16 bit quantity
                    return 0;
                *(pbyAddrCursor++) = nVal >> 8;     //transfer in network order
                *(pbyAddrCursor++) = nVal & 0xff;
                if ( ':' == **ppszText )    //typical case inside; carry on
                {
                    ++(*ppszText);
                }
                else    //some other terminating character; done with this parsing parts
                {
                    break;
                }
            }
        }
        
        //handle any zero compression we found
        if ( NULL != pbyZerosLoc )
        {
            int nHead = (int)( pbyZerosLoc - abyAddrLocal );    //how much before zero compression
            int nTail = nIdx * 2 - (int)( pbyZerosLoc - abyAddrLocal ); //how much after zero compression
            int nZeros = 16 - nTail - nHead;        //how much zeros
            memmove ( &abyAddrLocal[16-nTail], pbyZerosLoc, nTail );    //scootch stuff down
            memset ( pbyZerosLoc, 0, nZeros );      //clear the compressed zeros
        }
        
        //validation of ipv4 subspace ::ffff:x.x
        if ( bIPv4Detected )
        {
            static const unsigned char abyPfx[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
            if ( 0 != memcmp ( abyAddrLocal, abyPfx, sizeof(abyPfx) ) )
                return 0;
        }

        //close bracket
        if ( NULL != pchOpenBracket )
        {
            if ( ']' != **ppszText )
                return 0;
            ++(*ppszText);
        }

        if ( ':' == **ppszText && NULL != pnPort )  //have port part, and we want it
        {
            const char* pszTextBefore;
            unsigned int nVal;
            unsigned short usPortNetwork;   //save value in network order
            ++(*ppszText);  //past the colon
            pszTextBefore = *ppszText;
            pszTextBefore = *ppszText;
            nVal =_parseDecimal ( ppszText );
            if ( nVal > 65535 || pszTextBefore == *ppszText )
                return 0;
            ((unsigned char*)&usPortNetwork)[0] = ( nVal & 0xff00 ) >> 8;
            ((unsigned char*)&usPortNetwork)[1] = ( nVal & 0xff );
            *pnPort = usPortNetwork;
            return 1;
        }
        else    //finished just with ip address
        {
            if ( NULL != pnPort )
                *pnPort = 0;    //indicate we have no port part
            return 1;
        }
    }

}


//simple version if we want don't care about knowing how much we ate
int ParseIPv4OrIPv6_2 ( const char* pszText, 
        unsigned char* abyAddr, int* pnPort, int* pbIsIPv6 )
{
    const char* pszTextLocal = pszText;
    return ParseIPv4OrIPv6 ( &pszTextLocal, abyAddr, pnPort, pbIsIPv6);
}

Test:

#include <stdio.h>

... (above code for ParseIPv4OrIPv6 goes here) ...

unsigned short htons ( unsigned short us )
{
    return ( ((unsigned char*)&us)[0] << 8 ) + ((unsigned char*)&us)[1];
}

void dumpbin ( unsigned char* pbyBin, int nLen )
{
    int i;
    for ( i = 0; i < nLen; ++i )
    {
        printf ( "%02x", pbyBin[i] );
    }
}


void testcase ( const char* pszTest )
{
    unsigned char abyAddr[16];
    int bIsIPv6;
    int nPort;
    int bSuccess;

    printf ( "Test case '%s'\n", pszTest );
    const char* pszTextCursor = pszTest;
    bSuccess = ParseIPv4OrIPv6 ( &pszTextCursor, abyAddr, &nPort, &bIsIPv6 );
    if ( ! bSuccess )
    {
        printf ( "parse failed, at about index %d; rest: '%s'\n", pszTextCursor - pszTest, pszTextCursor );
        return;
    }
    
    printf ( "addr:  " );
    dumpbin ( abyAddr, bIsIPv6 ? 16 : 4 );
    printf ( "\n" );
    if ( 0 == nPort )
        printf ( "port absent" );
    else
        printf ( "port:  %d", htons ( nPort ) );
    printf ( "\n\n" );
    
}



int main ( int argc, char* argv[] )
{
    
    //The "localhost" IPv4 address
    testcase ( "127.0.0.1" );
    
    //The "localhost" IPv4 address, with a specified port (80)
    testcase ( "127.0.0.1:80" );
    //The "localhost" IPv6 address
    testcase ( "::1" );
    //The "localhost" IPv6 address, with a specified port (80)
    testcase ( "[::1]:80" );
    //Rosetta Code's primary server's public IPv6 address
    testcase ( "2605:2700:0:3::4713:93e3" );
    //Rosetta Code's primary server's public IPv6 address, with a specified port (80)
    testcase ( "[2605:2700:0:3::4713:93e3]:80" );
    
    //ipv4 space
    testcase ( "::ffff:192.168.173.22" );
    //ipv4 space with port
    testcase ( "[::ffff:192.168.173.22]:80" );
    //trailing compression
    testcase ( "1::" );
    //trailing compression with port
    testcase ( "[1::]:80" );
    //'any' address compression
    testcase ( "::" );
    //'any' address compression with port
    testcase ( "[::]:80" );
    
    return 0;
}

Output:

Test case '127.0.0.1'
addr:  7f000001
port absent

Test case '127.0.0.1:80'
addr:  7f000001
port:  80

Test case '::1'
addr:  00000000000000000000000000000001
port absent

Test case '[::1]:80'
addr:  00000000000000000000000000000001
port:  80

Test case '2605:2700:0:3::4713:93e3'
addr:  260527000000000300000000471393e3
port absent

Test case '[2605:2700:0:3::4713:93e3]:80'
addr:  260527000000000300000000471393e3
port:  80

Test case '::ffff:192.168.173.22'
addr:  00000000000000000000ffffc0a8ad16
port absent

Test case '[::ffff:192.168.173.22]:80'
addr:  00000000000000000000ffffc0a8ad16
port:  80

Test case '1::'
addr:  00010000000000000000000000000000
port absent

Test case '[1::]:80'
addr:  00010000000000000000000000000000
port:  80

Test case '::'
addr:  00000000000000000000000000000000
port absent

Test case '[::]:80'
addr:  00000000000000000000000000000000
port:  80

POSIX

Library: POSIX

The task is a bit easier on POSIX platforms where we can use the function inet_pton to parse IP addresses. This approach will also work on Microsoft Windows with some minor changes.

#include <arpa/inet.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

typedef struct ip_address_tag {
    union {
        uint8_t address_v6[16];
        uint32_t address_v4;
    } address;
    uint16_t family;
    uint16_t port;
} ip_address_t;

bool parse_ipv4_address(const char* input, ip_address_t* result) {
    struct in_addr addr;
    if (inet_pton(AF_INET, input, &addr) == 1) {
        result->family = AF_INET;
        result->address.address_v4 = ntohl(addr.s_addr);
        result->port = 0;
        return true;
    }
    return false;
}

bool parse_ipv6_address(const char* input, ip_address_t* result) {
    struct in6_addr addr;
    if (inet_pton(AF_INET6, input, &addr) == 1) {
        result->family = AF_INET6;
        memcpy(result->address.address_v6, addr.s6_addr, 16);
        result->port = 0;
        return true;
    }
    return false;
}

uint16_t parse_port_number(const char* str) {
    char* eptr;
    unsigned long port = strtoul(str, &eptr, 10);
    if (port > 0 && *eptr == '\0' && port <= UINT16_MAX)
        return (uint16_t)port;
    return 0;
}

//
// Parse an IP address and port from the given input string.
// Returns false if the input is not valid.
//
// Valid formats are:
// [ipv6_address]:port
// ipv4_address:port
// ipv4_address
// ipv6_address
//
bool parse_address(const char* input, ip_address_t* result) {
    char* ptr = strrchr(input, ':');
    if (ptr != NULL && ptr > input) {
        uint16_t port = parse_port_number(ptr + 1);
        if (port > 0) {
            bool success = false;
            char* copy = strdup(input);
            if (copy == NULL)
                return false;
            int index = ptr - input;
            copy[index] = '\0';
            if (copy[index - 1] == ']' && copy[0] == '[') {
                copy[index - 1] = '\0';
                if (parse_ipv6_address(copy + 1, result))
                    success = true;
            } else if (parse_ipv4_address(copy, result)) {
                success = true;
            }
            free(copy);
            if (success) {
                result->port = port;
                return true;
            }
        }
    }
    return parse_ipv6_address(input, result)
        || parse_ipv4_address(input, result);
}

void test_parse_address(const char* input) {
    printf("input: %s\n", input);
    ip_address_t result;
    if (parse_address(input, &result)) {
        printf("address family: %s\n",
               result.family == AF_INET ? "IPv4" : "IPv6");
        if (result.family == AF_INET)
            printf("address: %X", result.address.address_v4);
        else if (result.family == AF_INET6) {
            printf("address: ");
            for (int i = 0; i < 16; ++i)
                printf("%02X", (unsigned int)result.address.address_v6[i]);
        }
        printf("\n");
        if (result.port > 0)
            printf("port: %hu\n", result.port);
        else
            printf("port not specified\n");
    } else {
        printf("Parsing failed.\n");
    }
    printf("\n");
}

int main() {
    test_parse_address("127.0.0.1");
    test_parse_address("127.0.0.1:80");
    test_parse_address("::ffff:127.0.0.1");
    test_parse_address("::1");
    test_parse_address("[::1]:80");
    test_parse_address("1::80");
    test_parse_address("2605:2700:0:3::4713:93e3");
    test_parse_address("[2605:2700:0:3::4713:93e3]:80");
    return 0;
}
Output:
input: 127.0.0.1
address family: IPv4
address: 7F000001
port not specified

input: 127.0.0.1:80
address family: IPv4
address: 7F000001
port: 80

input: ::ffff:127.0.0.1
address family: IPv6
address: 00000000000000000000FFFF7F000001
port not specified

input: ::1
address family: IPv6
address: 00000000000000000000000000000001
port not specified

input: [::1]:80
address family: IPv6
address: 00000000000000000000000000000001
port: 80

input: 1::80
address family: IPv6
address: 00010000000000000000000000000080
port not specified

input: 2605:2700:0:3::4713:93e3
address family: IPv6
address: 260527000000000300000000471393E3
port not specified

input: [2605:2700:0:3::4713:93e3]:80
address family: IPv6
address: 260527000000000300000000471393E3
port: 80

C#

Translation of: Java
using System;
using System.Text.RegularExpressions;
using System.Text;

class ParseIPAddress
{
    private static readonly Regex IPV4_PAT = new Regex(@"^(\d+)\.(\d+)\.(\d+)\.(\d+)(?::(\d+)){0,1}$");
    private static readonly Regex IPV6_DOUBL_COL_PAT = new Regex(@"^\[{0,1}([0-9a-f:]*)::([0-9a-f:]*)(?:\]:(\d+)){0,1}$");
    private static readonly Regex IPV6_PAT;

    static ParseIPAddress()
    {
        string ipv6Pattern = @"^\[{0,1}";
        for (int i = 1; i <= 7; i++)
        {
            ipv6Pattern += @"([0-9a-f]+):";
        }
        ipv6Pattern += @"([0-9a-f]+)(?:\]:(\d+)){0,1}$";
        IPV6_PAT = new Regex(ipv6Pattern);
    }

    static void Main(string[] args)
    {
        string[] tests = new string[] { "192.168.0.1", "127.0.0.1", "256.0.0.1", "127.0.0.1:80", "::1", "[::1]:80", "[32e::12f]:80", "2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80", "2001:db8:85a3:0:0:8a2e:370:7334" };
        Console.WriteLine(String.Format("{0,-40} {1,-32}   {2}", "Test Case", "Hex Address", "Port"));
        foreach (var ip in tests)
        {
            try
            {
                string[] parsed = ParseIP(ip);
                Console.WriteLine(String.Format("{0,-40} {1,-32}   {2}", ip, parsed[0], parsed[1]));
            }
            catch (ArgumentException e)
            {
                Console.WriteLine(String.Format("{0,-40} Invalid address:  {1}", ip, e.Message));
            }
        }
    }
    
    

    private static string[] ParseIP(string ip)
    {
        string hex = "";
        string port = "";

        // IPV4
        Match ipv4Matcher = IPV4_PAT.Match(ip);
        if (ipv4Matcher.Success)
        {
            for (int i = 1; i <= 4; i++)
            {
                hex += ToHex4(ipv4Matcher.Groups[i].Value);
            }
            if (ipv4Matcher.Groups[5].Success)
            {
                port = ipv4Matcher.Groups[5].Value;
            }
            return new string[] { hex, port };
        }

        // IPV6, double colon        
        Match ipv6DoubleColonMatcher = IPV6_DOUBL_COL_PAT.Match(ip);
        if (ipv6DoubleColonMatcher.Success)
        {
            string p1 = ipv6DoubleColonMatcher.Groups[1].Value;
            if (p1 == "")
            {
                p1 = "0";
            }
            string p2 = ipv6DoubleColonMatcher.Groups[2].Value;
            if (p2 == "")
            {
                p2 = "0";
            }
            ip = p1 + GetZero(8 - NumCount(p1) - NumCount(p2)) + p2;
            if (ipv6DoubleColonMatcher.Groups[3].Success)
            {
                ip = "[" + ip + "]:" + ipv6DoubleColonMatcher.Groups[3].Value;
            }
        }

        // IPV6
        Match ipv6Matcher = IPV6_PAT.Match(ip);
        if (ipv6Matcher.Success)
        {
            for (int i = 1; i <= 8; i++)
            {
                hex += String.Format("{0,4}", ToHex6(ipv6Matcher.Groups[i].Value)).Replace(" ", "0");
            }
            if (ipv6Matcher.Groups[9].Success)
            {
                port = ipv6Matcher.Groups[9].Value;
            }
            return new string[] { hex, port };
        }

        throw new ArgumentException("ERROR 103: Unknown address: " + ip);
    }

    private static int NumCount(string s)
    {
        return s.Split(':').Length;
    }

    private static string GetZero(int count)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append(":");
        while (count > 0)
        {
            sb.Append("0:");
            count--;
        }
        return sb.ToString();
    }

    private static string ToHex4(string s)
    {
        int val = int.Parse(s);
        if (val < 0 || val > 255)
        {
            throw new ArgumentException("ERROR 101:  Invalid value : " + s);
        }
        return val.ToString("X2");
    }

    private static string ToHex6(string s)
    {
        int val = int.Parse(s, System.Globalization.NumberStyles.HexNumber);
        if (val < 0 || val > 65536)
        {
            throw new ArgumentException("ERROR 102:  Invalid hex value : " + s);
        }
        return s;
    }
}
Output:
Test Case                                Hex Address                        Port
192.168.0.1                              C0A80001                           
127.0.0.1                                7F000001                           
256.0.0.1                                Invalid address:  ERROR 101:  Invalid value : 256
127.0.0.1:80                             7F000001                           80
::1                                      00000000000000000000000000000001   
[::1]:80                                 00000000000000000000000000000001   80
[32e::12f]:80                            032e000000000000000000000000012f   80
2605:2700:0:3::4713:93e3                 260527000000000300000000471393e3   
[2605:2700:0:3::4713:93e3]:80            260527000000000300000000471393e3   80
2001:db8:85a3:0:0:8a2e:370:7334          20010db885a3000000008a2e03707334   

C++

Library: Boost
#include <boost/asio/ip/address.hpp>
#include <cstdint>
#include <iostream>
#include <iomanip>
#include <limits>
#include <string>

using boost::asio::ip::address;
using boost::asio::ip::address_v4;
using boost::asio::ip::address_v6;
using boost::asio::ip::make_address;
using boost::asio::ip::make_address_v4;
using boost::asio::ip::make_address_v6;

template<typename uint>
bool parse_int(const std::string& str, int base, uint& n) {
    try {
        size_t pos = 0;
        unsigned long u = stoul(str, &pos, base);
        if (pos != str.length() || u > std::numeric_limits<uint>::max())
            return false;
        n = static_cast<uint>(u);
        return true;
    } catch (const std::exception& ex) {
        return false;
    }
}

//
// Parse an IP address and port from the given input string.
//
// Throws an exception if the input is not valid.
//
// Valid formats are:
// [ipv6_address]:port
// ipv4_address:port
// ipv4_address
// ipv6_address
//
void parse_ip_address_and_port(const std::string& input, address& addr, uint16_t& port) {
    size_t pos = input.rfind(':');
    if (pos != std::string::npos && pos > 1 && pos + 1 < input.length()
        && parse_int(input.substr(pos + 1), 10, port) && port > 0) {
        if (input[0] == '[' && input[pos - 1] == ']') {
            // square brackets so can only be an IPv6 address
            addr = make_address_v6(input.substr(1, pos - 2));
            return;
        } else {
            try {
                // IPv4 address + port?
                addr = make_address_v4(input.substr(0, pos));
                return;
            } catch (const std::exception& ex) {
                // nope, might be an IPv6 address
            }
        }
    }
    port = 0;
    addr = make_address(input);
}

void print_address_and_port(const address& addr, uint16_t port) {
    std::cout << std::hex << std::uppercase << std::setfill('0');
    if (addr.is_v4()) {
        address_v4 addr4 = addr.to_v4();
        std::cout << "address family: IPv4\n";
        std::cout << "address number: " << std::setw(8) << addr4.to_uint() << '\n';
    } else if (addr.is_v6()) {
        address_v6 addr6 = addr.to_v6();
        address_v6::bytes_type bytes(addr6.to_bytes());
        std::cout << "address family: IPv6\n";
        std::cout << "address number: ";
        for (unsigned char byte : bytes)
            std::cout << std::setw(2) << static_cast<unsigned int>(byte);
        std::cout << '\n';
    }
    if (port != 0)
        std::cout << "port: " << std::dec << port << '\n';
    else
        std::cout << "port not specified\n";
}

void test(const std::string& input) {
    std::cout << "input: " << input << '\n';
    try {
        address addr;
        uint16_t port = 0;
        parse_ip_address_and_port(input, addr, port);
        print_address_and_port(addr, port);
    } catch (const std::exception& ex) {
        std::cout << "parsing failed\n";
    }
    std::cout << '\n';
}

int main(int argc, char** argv) {
    test("127.0.0.1");
    test("127.0.0.1:80");
    test("::ffff:127.0.0.1");
    test("::1");
    test("[::1]:80");
    test("1::80");
    test("2605:2700:0:3::4713:93e3");
    test("[2605:2700:0:3::4713:93e3]:80");
    return 0;
}
Output:
input: 127.0.0.1
address family: IPv4
address number: 7F000001
port not specified

input: 127.0.0.1:80
address family: IPv4
address number: 7F000001
port: 80

input: ::ffff:127.0.0.1
address family: IPv6
address number: 00000000000000000000FFFF7F000001
port not specified

input: ::1
address family: IPv6
address number: 00000000000000000000000000000001
port not specified

input: [::1]:80
address family: IPv6
address number: 00000000000000000000000000000001
port: 80

input: 1::80
address family: IPv6
address number: 00010000000000000000000000000080
port not specified

input: 2605:2700:0:3::4713:93e3
address family: IPv6
address number: 260527000000000300000000471393E3
port not specified

input: [2605:2700:0:3::4713:93e3]:80
address family: IPv6
address number: 260527000000000300000000471393E3
port: 80

F#

// Parse IP addresses: Nigel Galloway. May 29th., 2021
open System.Text.RegularExpressions
type ipv6= Complete |Composite |Compressed |CompressedComposite
let ip4n,ip6i,ip6g,ip6e,ip6l=let n,g="[0-9a-fA-F]{1,4}","(25[0-5])|(2[0-4]\d)|(1\d\d)|([1-9]?[0-9])" in (
  sprintf "^(%s)\.(%s)\.(%s)\.(%s)$" g g g g, sprintf "^(%s):(%s):(%s):(%s):(%s):(%s):(%s):(%s)$" n n n n n n n n,
  sprintf "^((%s):)?((%s):)?((%s):)?((%s):)?((%s):)?((%s):)?(^|%s)::(%s|$)(:(%s))?(:(%s))?(:(%s))?(:(%s))?(:(%s))?(:(%s))?$" n n n n n n n n n n n n n n,
  sprintf "^(%s):(%s):(%s):(%s):(%s):(%s):(%s)\.(%s)\.(%s)\.(%s)$" n n n n n n g g g g,
  sprintf "^((%s):)?((%s):)?((%s):)?((%s):)?(^|%s)::((%s):)?((%s):)?((%s):)?((%s):)?((%s):)?(%s)\.(%s)\.(%s)\.(%s)$" n n n n n n n n n n g g g g)
let mn,mi,mg,me,ml=[2;4;6;8;10;12;13], [14..2..26], [2;4;6;8;9], [11..2..19], [20..5..35]
let     fN(n:Match) g=g|>List.filter(fun(g:int)->n.Groups.[g].Length>0)
let     fI n (g:Match)=n|>List.fold(fun Σ (n:int)->(Σ<<<16)+((int>>bigint)(sprintf "0x%s" g.Groups.[n].Value)))0I
let rec fG n g=let a="0123456789abcdef" in match bigint.DivRem(n,16I) with (n,r) when n=0I->a.[int r]::g|>Array.ofList|>System.String |(n,r)->fG n (a.[int r]::g)
let     fE(m:Match) n g=(fN m n,fN m g)
let     fL n (g:Match)=n|>List.fold(fun Σ (n:int)->(Σ<<<8)+int(g.Groups.[n].Value))0
let (|IP4 |_|) n=let g=Regex.Match(n,ip4n) in if g.Success then Some(fL [1..5..16] g) else None
let (|IP6n|_|) i=let g=Regex.Match(i,ip6i) in if g.Success then Some(fI [1..8] g) else None
let (|IP6i|_|) g=let g=Regex.Match(g,ip6g) in if g.Success then let n,l=fE g mn mi in (if n.Length+l.Length<8 then Some(((fI n g)<<<((8-n.Length)*16))+(fI l g)) else None) else None
let (|IP6g|_|) e=let g=Regex.Match(e,ip6e) in if g.Success then Some(((fI [1..6] g)<<<32)+bigint(fL [7..5..22] g)) else None
let (|IP6e|_|) l=let g=Regex.Match(l,ip6l) in if g.Success then let n,l=fE g mg me in (if n.Length+l.Length<6 then Some(((fI n g)<<<((8-n.Length)*16))+((fI l g)<<<32)+bigint(fL ml g)) else None) else None
let (|IP6l|_|) n=match n with IP6n n->Some(Complete,fG n []) |IP6i n->Some(Compressed,fG n []) |IP6g n->Some(Composite,fG n []) |IP6e n->Some(CompressedComposite,fG n []) |_->None 
let (|IP4p|_|) n=let g=Regex.Match(n,"^(.+):(\d{1,4})$") in if g.Success then match g.Groups.[1].Value with IP4 n->Some(n,int g.Groups.[2].Value) |_->None else None
let (|IP6p|_|) n=let g=Regex.Match(n,"^\[(.+)\]:(\d{1,4})$") in if g.Success then match g.Groups.[1].Value with IP6l n->Some(n,int g.Groups.[2].Value) |_->None else None
let pIP n=match n with IP6p((t,g),p)->printfn "%s is a %A IPv6 address value 0x%s using port %d" n t g p 
                      |IP4 g->printfn "%s is an IPv4 address value %0x" n g
                      |IP6l(t,g)->printfn "%s is a %A IPv6 address value 0x%s" n t g
                      |IP4p(g,p)->printfn "%s is an IPv4 address value %0x using port %d" n g p
                      |_->printfn "%s not matched" n

["127.0.0.1";"127.0.0.1:80";"2605:2700:0:3::4713:93e3";"::1";"[::1]:80";"2605:2700:0:3::4713:93e3";"[2605:2700:0:3::4713:93e3]:80";
  "::ffff:127.0.0.1";"1:2:3:4:5:6:7:8";"1:2:3:4:5:6:7:8:9";"1:2:3:4:5:6:127.0.0.1"]|>List.iter pIP
Output:
127.0.0.1 is an IPv4 address value 7f000001
127.0.0.1:80 is an IPv4 address value 7f000001 using port 80
2605:2700:0:3::4713:93e3 is a Compressed IPv6 address value 0x260527000000000300000000471393e3
::1 is a Compressed IPv6 address value 0x1
[::1]:80 is a Compressed IPv6 address value 0x1 using port 80
2605:2700:0:3::4713:93e3 is a Compressed IPv6 address value 0x260527000000000300000000471393e3
[2605:2700:0:3::4713:93e3]:80 is a Compressed IPv6 address value 0x260527000000000300000000471393e3 using port 80
::ffff:127.0.0.1 is a CompressedComposite IPv6 address value 0xffff7f000001
1:2:3:4:5:6:7:8 is a Complete IPv6 address value 0x10002000300040005000600070008
1:2:3:4:5:6:7:8:9 not matched
1:2:3:4:5:6:127.0.0.1 is a Composite IPv6 address value 0x1000200030004000500067f000001

Go

package main

import (
	"encoding/hex"
	"fmt"
	"io"
	"net"
	"os"
	"strconv"
	"strings"
	"text/tabwriter"
)

// parseIPPort parses an IP with an optional port, returning an IP and a port (or nil
// if no port was present in the given address).
func parseIPPort(address string) (net.IP, *uint64, error) {
	ip := net.ParseIP(address)
	if ip != nil {
		return ip, nil, nil
	}

	host, portStr, err := net.SplitHostPort(address)
	if err != nil {
		return nil, nil, fmt.Errorf("splithostport failed: %w", err)
	}

	port, err := strconv.ParseUint(portStr, 10, 16)
	if err != nil {
		return nil, nil, fmt.Errorf("failed to parse port: %w", err)
	}

	ip = net.ParseIP(host)
	if ip == nil {
		return nil, nil, fmt.Errorf("failed to parse ip address")
	}

	return ip, &port, nil
}

func ipVersion(ip net.IP) int {
	if ip.To4() == nil {
		return 6
	}

	return 4
}

func main() {
	testCases := []string{
		"127.0.0.1",
		"127.0.0.1:80",
		"::1",
		"[::1]:443",
		"2605:2700:0:3::4713:93e3",
		"[2605:2700:0:3::4713:93e3]:80",
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)

	writeTSV := func(w io.Writer, args ...interface{}) {
		fmt.Fprintf(w, strings.Repeat("%s\t", len(args)), args...)
		fmt.Fprintf(w, "\n")
	}

	writeTSV(w, "Input", "Address", "Space", "Port")

	for _, addr := range testCases {
		ip, port, err := parseIPPort(addr)
		if err != nil {
			panic(err)
		}

		portStr := "n/a"
		if port != nil {
			portStr = fmt.Sprint(*port)
		}

		ipVersion := fmt.Sprintf("IPv%d", ipVersion(ip))

		writeTSV(w, addr, hex.EncodeToString(ip), ipVersion, portStr)
	}

	w.Flush()
}
Output:
Input                          Address                           Space  Port
127.0.0.1                      00000000000000000000ffff7f000001  IPv4
127.0.0.1:80                   00000000000000000000ffff7f000001  IPv4   80
::1                            00000000000000000000000000000001  IPv6
[::1]:443                      00000000000000000000000000000001  IPv6   443
2605:2700:0:3::4713:93e3       260527000000000300000000471393e3  IPv6
[2605:2700:0:3::4713:93e3]:80  260527000000000300000000471393e3  IPv6   80

Haskell

import Data.List (isInfixOf)
import Numeric (showHex)
import Data.Char (isDigit)

data IPChunk = IPv6Chunk String | IPv4Chunk (String, String) |
    IPv6WithPort [IPChunk] String | IPv6NoPort [IPChunk] |
    IPv4WithPort IPChunk String | IPv4NoPort IPChunk |
    IPInvalid | IPZeroSection | IPUndefinedWithPort String |
    IPUndefinedNoPort

instance Show IPChunk where
    show (IPv6Chunk a) = a
    show (IPv4Chunk (a,b)) = a ++ b
    show (IPv6WithPort a p) = "IPv6 " ++ concatMap show a ++ " port " ++ p
    show (IPv6NoPort a) = "IPv6 " ++ concatMap show a ++ " no port"
    show (IPv4WithPort a p) = "IPv4 " ++ show a ++ " port " ++ p
    show (IPv4NoPort a) = "IPv4 " ++ show a
    show IPInvalid = "Invalid IP address"
    
isIPInvalid IPInvalid = True
isIPInvalid _ = False

isIPZeroSection IPZeroSection = True
isIPZeroSection _ = False

splitOn _ [] = []
splitOn x xs = let (a, b) = break (== x) xs in a : splitOn x (drop 1 b)

count x = length . filter (== x)

between a b x = x >= a && x <= b

none f = all (not . f)

parse1 [] = IPInvalid
parse1 "::" = IPUndefinedNoPort
parse1 ('[':':':':':']':':':ps) = if portIsValid ps then IPUndefinedWithPort ps else IPInvalid
parse1 ('[':xs) = if "]:" `isInfixOf` xs
    then let (a, b) = break (== ']') xs in
            if tail b == ":" then IPInvalid else IPv6WithPort (map chunk (splitOn ':' a)) (drop 2 b)
    else IPInvalid
parse1 xs
    | count ':' xs <= 1 && count '.' xs == 3 =
        let (a, b) = break (== ':') xs in case b of
                "" -> IPv4NoPort (chunk a)
                (':':ps) -> IPv4WithPort (chunk a) ps
                _ -> IPInvalid
    | count ':' xs > 1 && count '.' xs <= 3 =
        IPv6NoPort (map chunk (splitOn ':' xs))
            
chunk [] = IPZeroSection
chunk xs
    | '.' `elem` xs = case splitOn '.' xs of
        [a,b,c,d] -> let [e,f,g,h] = map read [a,b,c,d]
                     in if all (between 0 255) [e,f,g,h]
                            then let [i,j,k,l] = map (\n -> fill 2 $ showHex n "") [e,f,g,h]
                                 in IPv4Chunk (i ++ j, k ++ l)
                            else IPInvalid
    | ':' `notElem` xs && between 1 4 (length xs) && all (`elem` "0123456789abcdef") xs = IPv6Chunk (fill 4 xs)
    | otherwise = IPInvalid 

fill n xs = replicate (n - length xs) '0' ++ xs

parse2 IPInvalid = IPInvalid
parse2 (IPUndefinedWithPort p) = IPv6WithPort (replicate 8 zeroChunk) p
parse2 IPUndefinedNoPort = IPv6NoPort (replicate 8 zeroChunk)
parse2 a = case a of
    IPv6WithPort xs p -> if none isIPInvalid xs && portIsValid p
        then let ys = complete xs
             in  if countChunks ys == 8
                     then IPv6WithPort ys p
                     else IPInvalid
        else IPInvalid
    IPv6NoPort xs -> if none isIPInvalid xs
        then let ys = complete xs
             in  if countChunks ys == 8
                     then IPv6NoPort ys
                     else IPInvalid
        else IPInvalid
    IPv4WithPort (IPv4Chunk a) p -> if portIsValid p
        then IPv4WithPort (IPv4Chunk a) p
        else IPInvalid
    IPv4NoPort (IPv4Chunk a) -> IPv4NoPort (IPv4Chunk a)
    _ -> IPInvalid

zeroChunk = IPv6Chunk "0000"

portIsValid a = all isDigit a && between 0 65535 (read a)

complete xs = case break isIPZeroSection xs of
    (_, [IPZeroSection]) -> []
    (ys, []) -> ys
    ([], (IPZeroSection:IPZeroSection:ys)) -> if any isIPZeroSection ys || countChunks ys > 7
        then []
        else replicate (8 - countChunks ys) zeroChunk ++ ys
    (ys, (IPZeroSection:zs)) -> if any isIPZeroSection zs || countChunks ys + countChunks zs > 7
        then []
        else ys ++ replicate (8 - countChunks ys - countChunks zs) zeroChunk ++ zs
    _ -> []

countChunks xs = foldl f 0 xs
    where f n (IPv4Chunk _) = n + 2
          f n (IPv6Chunk _) = n + 1
    
ip = parse2 . parse1

main = mapM_ (putStrLn . show . ip)
    ["127.0.0.1",                                  -- loop back
     "127.0.0.1:80",                               -- loop back +port
     "::1",                                        -- loop back
     "[::1]:80",                                   -- loop back +port
     "2605:2700:0:3::4713:93e3",                   -- Rosetta Code
     "[2605:2700:0:3::4713:93e3]:80"]              -- Rosetta Code

Output:

IPv4 7f000001
IPv4 7f000001 port 80
IPv6 00000000000000000000000000000001 no port
IPv6 00000000000000000000000000000001 port 80
IPv6 260527000000000300000000471393e3 no port
IPv6 260527000000000300000000471393e3 port 80

Icon and Unicon

link printf, hexcvt

procedure main()
   L := ["192.168.0.1",                                # private
         "127.0.0.1",                                  # loop back
         "127.0.0.1:80",                               # loop back +port
         "2001:db8:85a3:0:0:8a2e:370:7334",            # doc, IPv6 for 555-1234
         "2001:db8:85a3::8a2e:370:7334",               # doc
         "::1",                                        # loop back
         "[::1]:80",                                   # loop back +port
         "::",                                         # unspecified
         "::ffff:192.168.0.1",                         # transition
         "2605:2700:0:3::4713:93e3",                   # RC     
         "[2605:2700:0:3::4713:93e3]:80",              # RC 
         "::ffff:71.19.147.227",                       # RC transition
         "[::ffff:71.19.147.227]:80",                  # RC transition  +port        
         "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443", # doc +port
         "256.0.0.0",                                  # invalid
         "g::1"]                                       # invalid
                 
   every x := !L do {
      if x ?  (ip := ipmatch(), port := portmatch(), pos(0)) then {
         if i := IPv4decode(ip) then 
            printf("%s is the IPv4 address = x'%s'",x,i)
         else if i := IPv6decode(ip) then 
               printf("%s is the IPv6 address = x'%s'",x,i)
         else {
            printf("%s is not a valid IP address\n",x)
            next
            }
         if \port then printf(" port=%s\n",port) else printf("\n")
         }
      else printf("%s is not an IP address\n",x)
      }
end


procedure ipmatch()                                #: match an ip v4/v6 address
static c4,c6
initial {
   c4 := &digits ++ '.'
   c6 := &digits ++ 'abcdef:'
   }
   suspend (="[" || ( (="::ffff:" || tab(many(c4))) | tab(many(c6)) ) || ="]") |
           ( ="::ffff:" || tab(many(c4))) |  tab(many(c6|c4))
end

procedure portmatch()                              #: match a port number
   return (=":",0 < (65536 > tab(many(&digits)))) | &null
end

procedure IPv4decode(s)                            #: match IPv4 to hex string 
   s ? ( ip  := (0 <= (256 > tab(many(&digits)))), ip *:= 256, =".", 
         ip +:= (0 <= (256 > tab(many(&digits)))), ip *:= 256, =".",
         ip +:= (0 <= (256 > tab(many(&digits)))), ip *:= 256, =".",
         ip +:= (0 <= (256 > tab(many(&digits)))),
         return right(hexstring(ip,,&lcase),8) )            
end

procedure IPv6decode(s)                            #: IPv6 to hex string
   s ?:=  2(="[", tab(-1), ="]")                         # remove any [] 
   if find(".",s) then                                   # transitional
      s ? ( tab(many(':0')), ="ffff:", 
            return right("ffff" || IPv4decode(tab(0)),32,"0") )
   else { 
      h := t := ""
      s ? {
         while x := tab(find(":")) do {                  # head
            if *x <= 4 then h ||:= right(x,4,"0")
            if ="::" then break
            else move(1)
            }
         while x := tab(find(":")|0) do {                # tail 
            if *x <= 4 then t ||:= right(x,4,"0")          
            move(1) | break
            }
         if x := h || repl("0",32-(*h+*t)) || t then     # and insides
            return x
         }
      }
end

printf.icn provides the printf family hexcvt.icn provides hex and hexstring

Output:

192.168.0.1 is the IPv4 address = x'c0a80001'
127.0.0.1 is the IPv4 address = x'7f000001'
127.0.0.1:80 is the IPv4 address = x'7f000001' port=80
2001:db8:85a3:0:0:8a2e:370:7334 is the IPv6 address = x'20010db885a3000000008a2e03707334'
2001:db8:85a3::8a2e:370:7334 is the IPv6 address = x'20010db885a3000000008a2e03707334'
::1 is the IPv6 address = x'00000000000000000000000000000001'
[::1]:80 is the IPv6 address = x'00000000000000000000000000000001' port=80
:: is the IPv6 address = x'00000000000000000000000000000000'
::ffff:192.168.0.1 is the IPv6 address = x'00000000000000000000ffffc0a80001'
2605:2700:0:3::4713:93e3 is the IPv6 address = x'260527000000000300000000471393e3'
[2605:2700:0:3::4713:93e3]:80 is the IPv6 address = x'260527000000000300000000471393e3' port=80
::ffff:71.19.147.227 is the IPv6 address = x'00000000000000000000ffff471393e3'
[::ffff:71.19.147.227]:80 is the IPv6 address = x'00000000000000000000ffff471393e3' port=80
[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443 is the IPv6 address = x'20010db885a308d313198a2e03707348' port=443
256.0.0.0 is not a valid IP address
g::1 is not an IP address

J

Implementation:

parseaddr=:3 :0
  if. '.' e. y do.
    if. +./'::' E. y do.
      parsehybrid y
    else.
      parseipv4 y
    end.
  else.
    parseipv6 y
  end.
)

parseipv4=:3 :0
  'addr port'=. 2{.<;._2 y,'::'
  4,((4#256)#._&".;._1'.',addr),_".port
)

parseipv6=:3 :0
  'addr port'=. 2{.<;._2 (y-.'['),']]'
  split=. I. '::' E. addr
  a1=. 8{. dfh;._2 (split {. addr),8#':'
  a2=._8{. dfh;._1 (8#':'),split }. addr
  6,(65536x#.a1+a2),_".port-.':'
)

parsehybrid=:3 :0
  'kludge port'=. 2{.<;._2 (tolower y-.'['),']]'
  addr=. _1 {:: <;._2 kludge,':'
  assert. (kludge-:'::ffff:',addr) +. kludge-: '::',addr
  6,(16bffff00000000+1{parseipv4 addr),_".port-.':'
)

fmt=:3 :0
  port=. ''
  ((#y){.'v';'addr';'port')=. y
  'ipv',(":v),' ',(hfd addr),(#port)#' ',":port
)

Task examples:

   fmt parseaddr '127.0.0.1'
ipv4 7f000001
   fmt parseaddr '127.0.0.1:80'
ipv4 7f000001 80
   fmt parseaddr '::1'
ipv6 1
   fmt parseaddr '[::1]:80'
ipv6 1 80
   fmt parseaddr '2605:2700:0:3::4713:93e3'
ipv6 260527000000000300000000471393e3
   fmt parseaddr '[2605:2700:0:3::4713:93e3]:80'
ipv6 260527000000000300000000471393e3 80

The intermediate (unformatted) result from parseaddr is the protocol number (4 or 6), the address and optionally the port:

   parseaddr '127.0.0.1'
4 2130706433
   parseaddr '127.0.0.1:80'
4 2130706433 80
   parseaddr '::1'
6 1
   parseaddr '[::1]:80'
6 1 80
   parseaddr '2605:2700:0:3::4713:93e3'
6 50537416338094019778974086937420469219
   parseaddr '[2605:2700:0:3::4713:93e3]:80'
6 50537416338094019778974086937420469219 80

Java

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ParseIPAddress {

    public static void main(String[] args) {
        String [] tests = new String[] {"192.168.0.1", "127.0.0.1", "256.0.0.1", "127.0.0.1:80", "::1", "[::1]:80", "[32e::12f]:80", "2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80", "2001:db8:85a3:0:0:8a2e:370:7334"};
        System.out.printf("%-40s %-32s   %s%n", "Test Case", "Hex Address", "Port");
        for ( String ip : tests ) {
            try {
                String [] parsed = parseIP(ip);
                System.out.printf("%-40s %-32s   %s%n", ip, parsed[0], parsed[1]);
            }
            catch (IllegalArgumentException e) {
                System.out.printf("%-40s Invalid address:  %s%n", ip, e.getMessage());
            }
        }
    }
    
    private static final Pattern IPV4_PAT = Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)(?::(\\d+)){0,1}$");
    private static final Pattern IPV6_DOUBL_COL_PAT = Pattern.compile("^\\[{0,1}([0-9a-f:]*)::([0-9a-f:]*)(?:\\]:(\\d+)){0,1}$");
    private static String ipv6Pattern;
    static {
        ipv6Pattern = "^\\[{0,1}";
        for ( int i = 1 ; i <= 7 ; i ++ ) {
            ipv6Pattern += "([0-9a-f]+):";
        }
        ipv6Pattern += "([0-9a-f]+)(?:\\]:(\\d+)){0,1}$";
    }
    private static final Pattern IPV6_PAT = Pattern.compile(ipv6Pattern);
    
    private static String[] parseIP(String ip) {
        String hex = "";
        String port = "";
        
        //  IPV4
        Matcher ipv4Matcher = IPV4_PAT.matcher(ip);
        if ( ipv4Matcher.matches() ) {
            for ( int i = 1 ; i <= 4 ; i++ ) {
                hex += toHex4(ipv4Matcher.group(i));
            }
            if ( ipv4Matcher.group(5) != null ) {
                port = ipv4Matcher.group(5);
            }
            return new String[] {hex, port};
        }
        
        //  IPV6, double colon        
        Matcher ipv6DoubleColonMatcher = IPV6_DOUBL_COL_PAT.matcher(ip);
        if ( ipv6DoubleColonMatcher.matches() ) {
            String p1 = ipv6DoubleColonMatcher.group(1);
            if ( p1.isEmpty() ) {
                p1 = "0";
            }
            String p2 = ipv6DoubleColonMatcher.group(2);
            if ( p2.isEmpty() ) {
                p2 = "0";
            }
            ip =  p1 + getZero(8 - numCount(p1) - numCount(p2)) + p2;
            if ( ipv6DoubleColonMatcher.group(3) != null ) {
                ip = "[" + ip + "]:" + ipv6DoubleColonMatcher.group(3);
            }
        }
        
        //  IPV6
        Matcher ipv6Matcher = IPV6_PAT.matcher(ip);
        if ( ipv6Matcher.matches() ) {
            for ( int i = 1 ; i <= 8 ; i++ ) {
                hex += String.format("%4s", toHex6(ipv6Matcher.group(i))).replace(" ", "0");
            }
            if ( ipv6Matcher.group(9) != null ) {
                port = ipv6Matcher.group(9);
            }
            return new String[] {hex, port};
        }
        
        throw new IllegalArgumentException("ERROR 103: Unknown address: " + ip);
    }
    
    private static int numCount(String s) {
        return s.split(":").length;
    }
    
    private static String getZero(int count) {
        StringBuilder sb = new StringBuilder();
        sb.append(":");
        while ( count > 0 ) {
            sb.append("0:");
            count--;
        }
        return sb.toString();
    }

    private static String toHex4(String s) {
        int val = Integer.parseInt(s);
        if ( val < 0 || val > 255 ) {
            throw new IllegalArgumentException("ERROR 101:  Invalid value : " + s);
        }
        return String.format("%2s", Integer.toHexString(val)).replace(" ", "0");
    }

    private static String toHex6(String s) {
        int val = Integer.parseInt(s, 16);
        if ( val < 0 || val > 65536 ) {
            throw new IllegalArgumentException("ERROR 102:  Invalid hex value : " + s);
        }
        return s;
    }

}
Output:
Test Case                                Hex Address                        Port
192.168.0.1                              c0a80001                           
127.0.0.1                                7f000001                           
256.0.0.1                                Invalid address:  ERROR 101:  Invalid value : 256
127.0.0.1:80                             7f000001                           80
::1                                      00000000000000000000000000000001   
[::1]:80                                 00000000000000000000000000000001   80
[32e::12f]:80                            032e000000000000000000000000012f   80
2605:2700:0:3::4713:93e3                 260527000000000300000000471393e3   
[2605:2700:0:3::4713:93e3]:80            260527000000000300000000471393e3   80
2001:db8:85a3:0:0:8a2e:370:7334          20010db885a3000000008a2e03707334   

jq

Works with gojq, the Go implementation of jq.

Adapted from Wren

# Generic preliminaries

# To take advantage of gojq's arbitrary-precision integer arithmetic:
def power($b): . as $in | reduce range(0;$b) as $i (1; . * $in);

# To take advantage of gojq's arbitrary-precision integer arithmetic:
# if the input and $j are integers, then the result will be an integer.
def div($j):
  (. - (. % j)) / $j;

# integer to stream of 0s and 1s, least significant bit first
def bitwise:
  recurse( if . >= 2 then div(2) else empty end) | . % 2;

# inverse of `bitwise`
def stream_to_integer(stream):
  reduce stream as $c ( {power:1 , ans: 0};
      .ans += ($c * .power) | .power *= 2 )
    | .ans;

# Input determines the max number of bits to be retained
# $x and $y are two integers
def xorBits($x;$y):
   def lxor(a;b):
     if (a==1 or b==1) and ((a==1 and b==1)|not) then 1
     elif a == null then b
     elif b == null then a
     else 0
     end;
   if $x == 0 then $y
   elif $y == 0 then $x
   else
     [if . then limit(.; $x|bitwise) else $x|bitwise end] as $s
   | [if . then limit(.; $y|bitwise) else $y|bitwise end] as $t
   | stream_to_integer(
       range(0; [($s|length), ($t|length)] | max) as $i
       | lxor($s[$i]; $t[$i]) )
   end ;

# $x and $y are two integers
def xor($x;$y):
   null | xorBits($x;$y);

def count(stream): reduce stream as $i (0; .+1);

# Input: an array
def insert($i; $x): .[:$i] + [$x] + .[$i:];

# Input: a non-negative integer
def tobase($b):
  def digit: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[.:.+1];
  def mod: . % $b;
  def div: ((. - mod) / $b);
  def digits: recurse( select(. > 0) | div) | mod ;
  # For jq it would be wise to protect against `infinite` as input, but using `isinfinite` confuses gojq
  select( (tostring|test("^[0-9]+$")) and 2 <= $b and $b <= 36)
  | if . == 0 then "0"
    else [digits | digit] | reverse[1:] | add
    end;

# Input: a string in base $b
# Output: its decimal value
def frombase($b):
  def decimalValue:
    if   48 <= . and . <= 57 then . - 48
    elif 65 <= . and . <= 90 then . - 55  # (10+.-65)
    elif 97 <= . and . <= 122 then . - 87 # (10+.-97)
    else "decimalValue <- \(.)" | error
    end;
  reduce (explode|reverse[]|decimalValue) as $x ({p:1};
    .value += (.p * $x)
    | .p *= $b)
  | .value ;

### Parse an IP address

# An IPAddress is represented by an object {"address", "addressSpace", "port"}
# where addressSpace is one of "IPv4", "IPv6", "Invalid"
# and a port of -1 denotes 'not specified'.

def INVALID: {address: 0, addressSpace: "Invalid", port: 0};

def ipAddressParse:

  # Helper for octet1
  # Assumes .len == (.hextets|length)
  def fixhextets:
      .insertions = (8 - .len)
      | .i = 0
      | until(.i == 8;
          if .hextets[.i] == ""
          then .hextets[.i] = "0"
          | until( .insertions <= 0;
              .insertions += -1
              | .i as $i
              | .hextets |= insert($i; "0") )
              | .i = 8
          else .i += 1
          end ) ;
            
  # Handle the case when octet length is 4
  def octet4:  
      (.octets[0] | split(":")) as $split
      | if $split|length == 2
        then ($split[1]|tonumber? // null) as $temp
        | if $temp | (. == null or . < 0 or . > 65535)
          then .return = INVALID
          else .port = $temp
          | .octets[0] = $split[0]
          end
        else .
        end
      | if .return then .
        else reduce range(0;4) as $i (.;
          if .return then .
          else (.octets[$i] | tonumber? // null) as $num
          | if $num | (. == null or . < 0 or . > 255) then .return = INVALID
            else .address = xor(.address; $num * (2 | power($i * 8)))
            end
          end)
        end
      | if .return then .
        elif .trans
        then .address += 281470681743360 # "ffff00000000"
        else .
        end ;

  # Handle the case when octet length is 1
  def octet1:
      .addressSpace = "IPv6"
      | if .ipa[0:1] == "["
        then .ipa |= .[1:]
        | (.ipa | split("]:")) as $split
        | if $split|length != 2 then .return = INVALID
          else ($split[1] | tonumber? // null) as $temp
          | if $temp | (. == null or . < 0 or . > 65535) then .return = INVALID
            else .port = $temp
            | .ipa |= .[0: (-2 - ($split[1]|length))]
            end
          end
        else .
        end
      | if .return then .
        else .hextets = (.ipa | split(":")|reverse)
        | .len = (.hextets|length)
        | if .ipa|startswith("::")
          then .hextets[-1] = "0"
          elif .ipa|endswith("::")
          then .hextets[0] = "0"
          else .
          end
        | if .ipa == "::" then .hextets[1] = "0" else . end
        | if .len > 8 or (.len == 8 and any(.hextets[]; . == "")) or count(.hextets[] | select(. == "")) > 1
          then .return = INVALID
          else .
          end
        end
      | if .return then .
        elif .len < 8
        then fixhextets
        else .
        end
      | if .return then .
        else reduce range(0; 8) as $j (.;
            if .return then .
            else (.hextets[$j] | frombase(16)) as $num
            | if $num > 65535 then .return = INVALID
              else .address = xor(.address; $num * (2 | power($j * 16)))
              end
            end)
        end ;

  { addressSpace: "IPv4",
    ipa: ascii_downcase,
    port: -1,
    trans: false }
  | if (.ipa|startswith("::ffff:")) and (.ipa|test("[.]"))
    then .addressSpace = "IPv6"
    | .trans = true
    | .ipa |= .[7:]
    elif (.ipa|startswith("[::ffff:")) and (.ipa|test("[.]"))
    then .addressSpace = "IPv6"
    | .trans = true
    | .ipa |= (.[8:] | gsub("]";""))
    else .
    end
  | .octets = (.ipa | split(".") | reverse)
  | .address = 0
  | if .octets|length == 4
    then octet4
    elif .octets|length == 1
    then octet1
    else .return = INVALID
    end
  | if .return then .return
    else {address, addressSpace, port}
    end ;

# Examples
def ipas: 
    "127.0.0.1",
    "127.0.0.1:80",
    "::1",
    "[::1]:80",
    "2605:2700:0:3::4713:93e3",
    "[2605:2700:0:3::4713:93e3]:80",
    "::ffff:192.168.173.22",
    "[::ffff:192.168.173.22]:80",
    "1::",
    "::",
    "256.0.0.0",
    "::ffff:127.0.0.0.1"
;

ipas
| "IP address    : \(.)",
( ipAddressParse
| "Address       : \(.address|tobase(16))",
  "Address Space : \(.addressSpace)",
  "Port          : \(if .port == -1 then "not specified" else .port end)",
  ""
)

Invocation: gojq -nr -f parse-an-ip-address.jq

Output:

Exactly as for Wren


Julia

const testdata = ["127.0.0.1", "127.0.0.1:80", "::1", "[::1]:80",
                  "2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80",
                  "::ffff:192.168.173.22", "[::ffff:192.168.173.22]:80",
                  "1::", "[1::]:80", "::", "[::]:80"]

maybev4(ip) = search(ip, '.') > 0 && length(matchall(r":", ip)) < 2
maybev6(ip) = length(matchall(r":", ip)) > 1

function parseip(ip)
    if (mat = match(r"^\[([:.\da-fA-F]+)\]:(\d+)$", ip))!= nothing ||
       (mat = match(r"^([\d.]+)[:/](\d+)$", ip)) != nothing
        port = mat.captures[2]
        ip = mat.captures[1]
    else
        port = "none"
    end
    if maybev4(ip)
        println("Processing ip v4 $ip")
        iphex = hex(Int(Base.IPv4(ip)))
        addresspace = "IPv4"
    elseif maybev6(ip)
        println("Processing ip v6 $ip")
        iphex = hex(UInt128(Base.IPv6(ip)))
        addresspace = "IPv6"
    else
        throw("Bad IP address argument $ip")
    end
    iphex, addresspace, port
end

for ip in testdata
    hx, add, por = parseip(ip)
    println("For input $ip, IP in hex is $hx, address space $add, port $por.")
end
Output:
Processing ip v4 127.0.0.1
For input 127.0.0.1, IP in hex is 7f000001, address space IPv4, port none.
Processing ip v4 127.0.0.1
For input 127.0.0.1:80, IP in hex is 7f000001, address space IPv4, port 80.
Processing ip v6 ::1
For input ::1, IP in hex is 1, address space IPv6, port none.
Processing ip v6 ::1
For input [::1]:80, IP in hex is 1, address space IPv6, port 80.
Processing ip v6 2605:2700:0:3::4713:93e3
For input 2605:2700:0:3::4713:93e3, IP in hex is 260527000000000300000000471393e3, address space IPv6, port none.
Processing ip v6 2605:2700:0:3::4713:93e3
For input [2605:2700:0:3::4713:93e3]:80, IP in hex is 260527000000000300000000471393e3, address space IPv6, port 80.
Processing ip v6 ::ffff:192.168.173.22
For input ::ffff:192.168.173.22, IP in hex is ffffc0a8ad16, address space IPv6, port none.
Processing ip v6 ::ffff:192.168.173.22
For input [::ffff:192.168.173.22]:80, IP in hex is ffffc0a8ad16, address space IPv6, port 80.
Processing ip v6 1::
For input 1::, IP in hex is 10000000000000000000000000000, address space IPv6, port none.
Processing ip v6 1::
For input [1::]:80, IP in hex is 10000000000000000000000000000, address space IPv6, port 80.
Processing ip v6 ::
For input ::, IP in hex is 0, address space IPv6, port none.
Processing ip v6 ::
For input [::]:80, IP in hex is 0, address space IPv6, port 80.

Kotlin

// version 1.1.3

import java.math.BigInteger

enum class AddressSpace { IPv4, IPv6, Invalid }

data class IPAddressComponents(
    val address: BigInteger,
    val addressSpace: AddressSpace,
    val port: Int  // -1 denotes 'not specified'
)

val INVALID = IPAddressComponents(BigInteger.ZERO, AddressSpace.Invalid, 0)
  
fun ipAddressParse(ipAddress: String): IPAddressComponents {
    var addressSpace = AddressSpace.IPv4
    var ipa = ipAddress.toLowerCase()
    var port = -1
    var trans = false
    
    if (ipa.startsWith("::ffff:") && '.' in ipa) {
        addressSpace = AddressSpace.IPv6
        trans = true
        ipa = ipa.drop(7)
    }
    else if (ipa.startsWith("[::ffff:") && '.' in ipa) {
        addressSpace = AddressSpace.IPv6
        trans = true
        ipa = ipa.drop(8).replace("]", "")
    } 
    val octets = ipa.split('.').reversed().toTypedArray()
    var address = BigInteger.ZERO
    if (octets.size == 4) {
        val split = octets[0].split(':')
        if (split.size == 2) {
            val temp = split[1].toIntOrNull()
            if (temp == null || temp !in 0..65535) return INVALID                
            port = temp
            octets[0] = split[0]
        }
       
        for (i in 0..3) {
            val num = octets[i].toLongOrNull()
            if (num == null || num !in 0..255) return INVALID
            val bigNum = BigInteger.valueOf(num)
            address = address.or(bigNum.shiftLeft(i * 8))
        }

        if (trans) address += BigInteger("ffff00000000", 16)
    }
    else if (octets.size == 1) {
        addressSpace = AddressSpace.IPv6
        if (ipa[0] == '[') {
            ipa = ipa.drop(1)
            val split = ipa.split("]:")
            if (split.size != 2) return INVALID
            val temp = split[1].toIntOrNull()
            if (temp == null || temp !in 0..65535) return INVALID
            port = temp
            ipa = ipa.dropLast(2 + split[1].length)
        }
        val hextets = ipa.split(':').reversed().toMutableList()
        val len = hextets.size

        if (ipa.startsWith("::")) 
            hextets[len - 1] = "0"
        else if (ipa.endsWith("::")) 
            hextets[0] = "0"

        if (ipa == "::") hextets[1] = "0"        
        if (len > 8 || (len == 8 && hextets.any { it == "" }) || hextets.count { it == "" } > 1)
            return INVALID
        if (len < 8) {
            var insertions = 8 - len            
            for (i in 0..7) {
                if (hextets[i] == "") {
                    hextets[i] = "0"
                    while (insertions-- > 0) hextets.add(i, "0") 
                    break 
                }
            } 
        }
        for (j in 0..7) {
            val num = hextets[j].toLongOrNull(16)
            if (num == null || num !in 0x0..0xFFFF) return INVALID
            val bigNum = BigInteger.valueOf(num)
            address = address.or(bigNum.shiftLeft(j * 16))
        }   
    }
    else return INVALID

    return IPAddressComponents(address, addressSpace, port)
}

fun main(args: Array<String>) {
    val ipas = listOf(
        "127.0.0.1",
        "127.0.0.1:80",
        "::1",
        "[::1]:80",
        "2605:2700:0:3::4713:93e3",
        "[2605:2700:0:3::4713:93e3]:80",
        "::ffff:192.168.173.22",
        "[::ffff:192.168.173.22]:80",
        "1::",
        "::",
        "256.0.0.0",
        "::ffff:127.0.0.0.1"
    )
    for (ipa in ipas) {
        val (address, addressSpace, port) = ipAddressParse(ipa)
        println("IP address    : $ipa")
        println("Address       : ${"%X".format(address)}") 
        println("Address Space : $addressSpace")
        println("Port          : ${if (port == -1) "not specified" else port.toString()}")
        println()
    } 
}
Output:
IP address    : 127.0.0.1
Address       : 7F000001
Address Space : IPv4
Port          : not specified

IP address    : 127.0.0.1:80
Address       : 7F000001
Address Space : IPv4
Port          : 80

IP address    : ::1
Address       : 1
Address Space : IPv6
Port          : not specified

IP address    : [::1]:80
Address       : 1
Address Space : IPv6
Port          : 80

IP address    : 2605:2700:0:3::4713:93e3
Address       : 260527000000000300000000471393E3
Address Space : IPv6
Port          : not specified

IP address    : [2605:2700:0:3::4713:93e3]:80
Address       : 260527000000000300000000471393E3
Address Space : IPv6
Port          : 80

IP address    : ::ffff:192.168.173.22
Address       : FFFFC0A8AD16
Address Space : IPv6
Port          : not specified

IP address    : [::ffff:192.168.173.22]:80
Address       : FFFFC0A8AD16
Address Space : IPv6
Port          : 80

IP address    : 1::
Address       : 10000000000000000000000000000
Address Space : IPv6
Port          : not specified

IP address    : ::
Address       : 0
Address Space : IPv6
Port          : not specified

IP address    : 256.0.0.0
Address       : 0
Address Space : Invalid
Port          : 0

IP address    : ::ffff:127.0.0.0.1
Address       : 0
Address Space : Invalid
Port          : 0

Nim

import net, sequtils, strscans, strutils

const NoPort = -1

func parseIpAddressAndPort(str: string): tuple[ipAddr: IpAddress; port: int] =
  var ipString: string
  var port: int
  if str.scanf("[$+]:$i", ipString, port):
    # IP v6 address with port.
    return (ipString.parseIpAddress(), port)
  if '.' in str and str.scanf("$+:$i", ipString, port):
    # IP v4 address with port.
    return (ipString.parseIpAddress(), port)
  # IP address without port.
  result = (str.parseIpAddress(), NoPort)


const Inputs = ["127.0.0.1", "127.0.0.1:80",
                "::1", "[::1]:80",
                "2605:2700:0:3::4713:93e3",
                "[2605:2700:0:3::4713:93e3]:80"]

# Room to reserve to display the input.
const InputSize = Inputs.mapIt(it.len).foldl(max(a, b)) + 2

echo "Input".alignLeft(InputSize), "Address".align(32), "  Space", "  Port"

for input in Inputs:
  try:
    let (ipAddress, port) = input.parseIpAddressAndPort()
    let portStr = if port == NoPort: "" else: $port
    case ipAddress.family
    of IPv6:
      echo input.alignLeft(InputSize),
           ipAddress.address_v6.map(toHex).join().align(32),
           "IP v6".align(7),
           portStr.align(6)
    of IPv4:
      echo input.alignLeft(InputSize),
           ipAddress.address_v4.map(toHex).join().align(32),
           "IP v4".align(7),
           portStr.align(6)

  except ValueError:
    echo "Invalid IP address: ", input
Output:
Input                                                   Address  Space  Port
127.0.0.1                                              7F000001  IP v4      
127.0.0.1:80                                           7F000001  IP v4    80
::1                            00000000000000000000000000000001  IP v6      
[::1]:80                       00000000000000000000000000000001  IP v6    80
2605:2700:0:3::4713:93e3       260527000000000300000000471393E3  IP v6      
[2605:2700:0:3::4713:93e3]:80  260527000000000300000000471393E3  IP v6    80

Perl

sub parse_v4 {
    my ($ip, $port) = @_;
    my @quad = split(/\./, $ip);

    return unless @quad == 4;
    for (@quad) { return if ($_ > 255) }

    if (!length $port) { $port = -1 }
    elsif ($port =~ /^(\d+)$/) { $port = $1 }
    else { return }

    my $h = join '' => map(sprintf("%02x", $_), @quad);
    return $h, $port
}

sub parse_v6 {
    my $ip = shift;
    my $omits;

    return unless $ip =~ /^[\da-f:.]+$/i; # invalid char

    $ip =~ s/^:/0:/;
    $omits = 1 if $ip =~ s/::/:z:/g;
    return if $ip =~ /z.*z/;    # multiple omits illegal

    my $v4 = '';
    my $len = 8;

    if ($ip =~ s/:((?:\d+\.){3}\d+)$//) {
        # hybrid 4/6 ip
        ($v4) = parse_v4($1)    or return;
        $len -= 2;

    }
    # what's left should be v6 only
    return unless $ip =~ /^[:a-fz\d]+$/i;

    my @h = split(/:/, $ip);
    return if @h + $omits > $len;   # too many segments

    @h = map( $_ eq 'z' ? (0) x ($len - @h + 1) : ($_), @h);
    return join('' => map(sprintf("%04x", hex($_)), @h)).$v4;
}

sub parse_ip {
    my $str = shift;
    $str =~ s/^\s*//;
    $str =~ s/\s*$//;

    if ($str =~ s/^((?:\d+\.)+\d+)(?::(\d+))?$//) {
        return 'v4', parse_v4($1, $2);
    }

    my ($ip, $port);
    if ($str =~ /^\[(.*?)\]:(\d+)$/) {
        $port = $2;
        $ip = parse_v6($1);
    } else {
        $port = -1;
        $ip = parse_v6($str);
    }

    return unless $ip;
    return 'v6', $ip, $port;
}

for (qw/127.0.0.1 127.0.0.1:80
    ::1
    [::1]:80
    2605:2700:0:3::4713:93e3
    [2605:2700:0:3::4713:93e3]:80
    ::ffff:192.168.0.1
    [::ffff:192.168.0.1]:22
    ::ffff:127.0.0.0.1
    a::b::1/)
{
    print "$_\n\t";
    my ($ver, $ip, $port) = parse_ip($_)
        or print "parse error\n" and next;

    print "$ver $ip\tport $port\n\n";
}

output

127.0.0.1
        v4 7f000001     port -1

127.0.0.1:80
        v4 7f000001     port 80

::1
        v6 00000000000000000000000000000001     port -1

[::1]:80
        v6 00000000000000000000000000000001     port 80

2605:2700:0:3::4713:93e3
        v6 260527000000000300000000471393e3     port -1

[2605:2700:0:3::4713:93e3]:80
        v6 260527000000000300000000471393e3     port 80

::ffff:192.168.0.1
        v6 00000000000000000000ffffc0a80001     port -1

[::ffff:192.168.0.1]:22
        v6 00000000000000000000ffffc0a80001     port 22

::ffff:127.0.0.0.1
        parse error
a::b::1
        parse error

Phix

with javascript_semantics
function parse_ip(string txt)
    sequence r
    integer dot = find('.',txt),
            colon = find(':',txt),
            openbr = find('[',txt),
            closebr = find(']',txt)
    if (colon=5 and txt[1..4] = "http")
    or (colon=6 and txt[1..5] = "https") then 
        txt = trim(txt[colon+1..$],"/")
        return parse_ip(txt)
    end if
    bool ipv6 = openbr or dot=0 or (colon and colon<dot)
    if ipv6 then
        sequence res = repeat(0,8)
        if openbr then
            if openbr!=1 or closebr<openbr then return 0 end if
            r = scanf(txt[closebr+1..$],":%d")
            if length(r)!=1 then return 0 end if
            atom port = r[1][1]
            if port<0 or port>65535 then return 0 end if
            res &= port
            txt = txt[2..closebr-1]
        end if
        if dot then
            colon = rfind(':',txt)
            if colon>dot then return 0 end if
            object r4 = parse_ip(txt[colon+1..$])
            if not sequence(r4) or length(r4)!=4 then return 0 end if
            res[7] = r4[1]*#100+r4[2]
            res[8] = r4[3]*#100+r4[4]
            txt = txt[1..colon-1+(txt[colon-1]=':')]
            dot = 2
        end if
        sequence r8 = {}
        integer ip = 0
        while length(txt) do
            colon = find(':',txt)
            if colon=1 then
                if ip then return 0 end if
                ip = length(r8)+1
                txt = txt[2+(length(r8)=0)..$]
            else
                r = scanf(txt[1..colon-1],"%x")
                if length(r)!=1 then return 0 end if
                atom r11 = r[1][1]
                if r11<0 or r11>#FFFF then return 0 end if
                r8 &= r11
                if colon=0 then exit end if
                txt = txt[colon+1..$]
            end if
        end while
        if ip then
            if length(r8)>=(8-dot) then return 0 end if
            r8[ip..ip-1] = repeat(0,(8-dot)-length(r8))
        else
            if length(r8)!=8-dot then return 0 end if
        end if
        res[1..8-dot] = r8
        return res
    end if
    -- ipv4:
    if dot=0 or (colon and colon<dot) then return 0 end if
    string d4 = substitute(txt[1..colon-1],'.',' ')
    r = scanf(d4,"%d %d %d %d")
    if length(r)!=1 then return 0 end if
    r = r[1]
    for i=1 to length(r) do
        if r[i]<0 or r[i]>255 then return 0 end if
    end for
    if colon then
        sequence r2 = scanf(txt[colon+1..$],"%d")
        if length(r2)!=1 then return 0 end if
        atom port = r2[1][1]
        if port<0 or port>65535 then return 0 end if
        r &= port
    end if
    return r
end function
 
constant tests = {{"127.0.0.1",{127,0,0,1}},
                  {"127.0.0.1:80",{127,0,0,1,80}},
                  {"::1",{0,0,0,0,0,0,0,1}},
                  {"[::1]:80",{0,0,0,0,0,0,0,1,80}},
                  {"2605:2700:0:3::4713:93e3",{#2605,#2700,0,3,0,0,#4713,#93e3}},
                  {"[2605:2700:0:3::4713:93e3]:80",{#2605,#2700,0,3,0,0,#4713,#93e3,80}},
                  {"::ffff:192.168.173.22",{0,0,0,0,0,#ffff,#c0a8,#ad16}},
                  {"[::ffff:192.168.173.22]:80",{0,0,0,0,0,#ffff,#c0a8,#ad16,80}},
                  {"1::",{1,0,0,0,0,0,0,0}},
                  {"[1::]:80",{1,0,0,0,0,0,0,0,80}},
                  {"::",{0,0,0,0,0,0,0,0}},
                  {"[::]:80",{0,0,0,0,0,0,0,0,80}},
                  {"192.168.0.1",{192,168,0,1}},
                  {"2001:db8:85a3:0:0:8a2e:370:7334",{#2001,#db8,#85a3,0,0,#8a2e,#370,#7334}},
                  {"2001:db8:85a3::8a2e:370:7334",{#2001,#db8,#85a3,0,0,#8a2e,#370,#7334}},
                  {"[2001:db8:85a3:8d3:1319:8a2e:370:7334]:443",{#2001,#db8,#85a3,#8d3,#1319,#8a2e,#370,#7334,443}},
                  {"256.0.0.0",0},
                  {"g::1",0},
                  {"::ffff:127.0.0.0.1",0},
                  {"a::b::1",0},
                  {"0000",0},
                  {"0000:0000",0},
                  {"0000:0000:0000:0000:0000:0000:0000:0000",{0,0,0,0,0,0,0,0}},
                  {"0000:0000:0000::0000:0000",{0,0,0,0,0,0,0,0}},
                  {"0000::0000::0000:0000",0},
                  {"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",{#ffff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff}},
                  {"ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff",0},
                  {"fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",{#fff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff,#ffff}},
                  {"fff:ffff:0:ffff:ffff:ffff:ffff:ffff",{#fff,#ffff,0,#ffff,#ffff,#ffff,#ffff,#ffff}},
                  {"2001:0db8:0:0:0:0:1428:57ab",{#2001,#0db8,0,0,0,0,#1428,#57ab}},
                  {"2001:0db8::1428:57ab",{#2001,#0db8,0,0,0,0,#1428,#57ab}},
                  {"2001:0db8:0:0:8d3:0:0:0",{#2001,#0db8,0,0,#8d3,0,0,0}},
                  {"2001:0db8:0:0:8d3::",{#2001,#0db8,0,0,#8d3,0,0,0}},
                  {"2001:0db8::8d3:0:0:0",{#2001,#0db8,0,0,#8d3,0,0,0}},
                  {"http://127.0.0.1/",{127,0,0,1}},
                  {"https://127.0.0.1/",{127,0,0,1}},
                  {"http:",0},
                  {"http:/2001:db8:3:4::127.0.2.0",{#2001,#db8,3,4,0,0,#7F00,#200}},
                  {"::192.168.0.1",{0,0,0,0,0,0,#C0A8,1}},
                  {"::ffff:0:255.255.255.255",{0,0,0,0,#ffff,0,#ffff,#ffff}},
                  {"",0},
                  {"ffffffffffffffffffffffffffffffff::",0},
                  {"[1::]:9999999999999999999999999999",0},
                  {"I think that's enough tests for now",0}}
 
for i=1 to length(tests) do
    {string ip, object expected} = tests[i]
    object actual = parse_ip(ip)
    if actual!=expected then
        ?{ip,actual,expected}
        ?9/0
    end if
    string addr
    if actual=0 then
        addr = "**not a valid ip address**"
    else
        if remainder(length(actual),2) then
            actual[$] = sprintf(", port %d",actual[$])
        else
            actual = append(actual,"")
        end if
        if length(actual)=5 then
            addr = sprintf("ivp4 address: %02x%02x%02x%02x%s",actual)
        elsif length(actual)=9 then
            addr = sprintf("ivp6 address: %04x%04x%04x%04x%04x%04x%04x%04x%s",actual)
        else
            ?9/0
        end if
    end if
    printf(1,"%45s %s\n",{ip,addr})
end for
Output:
                                    127.0.0.1 ivp4 address: 7F000001
                                 127.0.0.1:80 ivp4 address: 7F000001, port 80
                                          ::1 ivp6 address: 00000000000000000000000000000001
                                     [::1]:80 ivp6 address: 00000000000000000000000000000001, port 80
                     2605:2700:0:3::4713:93e3 ivp6 address: 260527000000000300000000471393E3
                [2605:2700:0:3::4713:93e3]:80 ivp6 address: 260527000000000300000000471393E3, port 80
                        ::ffff:192.168.173.22 ivp6 address: 00000000000000000000FFFFC0A8AD16
                   [::ffff:192.168.173.22]:80 ivp6 address: 00000000000000000000FFFFC0A8AD16, port 80
                                          1:: ivp6 address: 00010000000000000000000000000000
                                     [1::]:80 ivp6 address: 00010000000000000000000000000000, port 80
                                           :: ivp6 address: 00000000000000000000000000000000
                                      [::]:80 ivp6 address: 00000000000000000000000000000000, port 80
                                  192.168.0.1 ivp4 address: C0A80001
              2001:db8:85a3:0:0:8a2e:370:7334 ivp6 address: 20010DB885A3000000008A2E03707334
                 2001:db8:85a3::8a2e:370:7334 ivp6 address: 20010DB885A3000000008A2E03707334
   [2001:db8:85a3:8d3:1319:8a2e:370:7334]:443 ivp6 address: 20010DB885A308D313198A2E03707334, port 443
                                    256.0.0.0 **not a valid ip address**
                                         g::1 **not a valid ip address**
                           ::ffff:127.0.0.0.1 **not a valid ip address**
                                      a::b::1 **not a valid ip address**
                                         0000 **not a valid ip address**
                                    0000:0000 **not a valid ip address**
      0000:0000:0000:0000:0000:0000:0000:0000 ivp6 address: 00000000000000000000000000000000
                    0000:0000:0000::0000:0000 ivp6 address: 00000000000000000000000000000000
                        0000::0000::0000:0000 **not a valid ip address**
      ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ivp6 address: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
      ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff **not a valid ip address**
       fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ivp6 address: 0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
          fff:ffff:0:ffff:ffff:ffff:ffff:ffff ivp6 address: 0FFFFFFF0000FFFFFFFFFFFFFFFFFFFF
                  2001:0db8:0:0:0:0:1428:57ab ivp6 address: 20010DB80000000000000000142857AB
                         2001:0db8::1428:57ab ivp6 address: 20010DB80000000000000000142857AB
                      2001:0db8:0:0:8d3:0:0:0 ivp6 address: 20010DB80000000008D3000000000000
                          2001:0db8:0:0:8d3:: ivp6 address: 20010DB80000000008D3000000000000
                         2001:0db8::8d3:0:0:0 ivp6 address: 20010DB80000000008D3000000000000
                            http://127.0.0.1/ ivp4 address: 7F000001
                           https://127.0.0.1/ ivp4 address: 7F000001
                                        http: **not a valid ip address**
                http:/2001:db8:3:4::127.0.2.0 ivp6 address: 20010DB800030004000000007F000200
                                ::192.168.0.1 ivp6 address: 000000000000000000000000C0A80001
                     ::ffff:0:255.255.255.255 ivp6 address: 0000000000000000FFFF0000FFFFFFFF
                                              **not a valid ip address**
           ffffffffffffffffffffffffffffffff:: **not a valid ip address**
           [1::]:9999999999999999999999999999 **not a valid ip address**
          I think that's enough tests for now **not a valid ip address**

PicoLisp

# Return a cons pair of address and port: (address . port)
(de ipAddress (Adr)
   (use (@A @B @C @D @Port)
      (cond
         ((match '("[" @A "]" ":" @Port) Adr)
            (adrIPv6 (split @A ":") @Port) )
         ((match '("[" @A "]") Adr)
            (adrIPv6 (split @A ":")) )
         ((match '(@A ":" @B ":" @C) Adr)
            (adrIPv6 (cons @A @B (split @C ":"))) )
         ((match '(@A "." @B "." @C "." @D ":" @Port) Adr)
            (adrIPv4 (list @A @B @C @D) @Port) )
         ((match '(@A "." @B "." @C "." @D) Adr)
            (adrIPv4 (list @A @B @C @D)) )
         (T (quit "Bad IP address" (pack Adr))) ) ) )

(de adrIPv4 (Lst Port)
   (cons
      (sum >> (-24 -16 -8 0) (mapcar format Lst))
      (format Port) ) )

(de adrIPv6 (Lst Port)
   (cons
      (sum >>
         (-112 -96 -80 -64 -48 -32 -16 0)
         (mapcan
            '((X)
               (if X
                  (cons (hex X))
                  (need (- 9 (length Lst)) 0) ) )  # Handle '::'
            (cons (or (car Lst) "0") (cdr Lst)) ) )
      (format Port) ) )

Test:

(for A
   (quote
      "127.0.0.1"
      "127.0.0.1:80"
      "::1"
      "[::1]:80"
      "2605:2700:0:3::4713:93e3"
      "[2605:2700:0:3::4713:93e3]:80" )
   (let I (ipAddress (chop A))
      (tab (-29 34 40 7)
         A
         (hex (car I))
         (format (car I))
         (cdr I) ) ) )

Output:

127.0.0.1                                              7F000001                              2130706433
127.0.0.1:80                                           7F000001                              2130706433     80
::1                                                           1                                       1
[::1]:80                                                      1                                       1     80
2605:2700:0:3::4713:93e3       260527000000000300000000471393E3  50537416338094019778974086937420469219
[2605:2700:0:3::4713:93e3]:80  260527000000000300000000471393E3  50537416338094019778974086937420469219     80

PL/I

*process or(!) source xref attributes macro options;
 /*********************************************************************
 * Program to parse an IP address into -->   IPv4 or IPv6 format
 * 28.05.2013 Walter Pachl translated from REXX version 3
 *                         x2d was the hard part :-)
 *********************************************************************/
 ip: proc options(main);
 Dcl ipa   char(50) Var;
 Dcl ipi   char(50) Var;
 Dcl ipax  char(50) Var Init('');
 Dcl ipad  char(50) Var Init('');
 Dcl space char(4);
 Dcl port  char(5) Var;
 dcl head Char(132) Var;
 head='       input IP address                 hex IP address   '!!
      '                 decimal IP address            space  port';
 Put Edit(head)(Skip,a);
 Put Edit(copies('_',30),
          copies('_',32),
          copies('_',39),
          copies('_', 5),
          copies('_', 5))
         (Skip,6(a,x(1)));

 call expand('127.0.0.1');
 call expand('127.0.0.1:80');
 call expand('2605:2700:0:3::4713:93e3');
 call expand('[2605:2700:0:3::4713:93e3]:80');
 call expand('::1');
 call expand('[::1]:80');

 expand: procedure(s);
 Dcl s Char(50) Var;
 ipi=s;
 ipa=s;
 If index(ipa,'.')>0 Then
   Call expand_ipv4;
 Else
   Call expand_ipv6;
 ipad=x2d(ipax);
 Put Edit(left(ipi,30),right(ipax,32),right(ipad,39),
          right(space,5),right(port,5))
         (Skip,6(a,x(1)));
 End;

 expand_ipv4: Proc;
 Dcl a(4) Char(3) Var;
 Dcl (pp,j) Bin Fixed(31);
 space='IPv4';
 pp=index(ipa,':');
 If pp>0 Then Do;
   port=substr(ipa,pp+1);
   ipa=left(ipa,pp-1);
   End;
 Else
   Port='';
 Call parse((ipa),'.',a);
 ipax='';
 do j=1 To 4;
   ipax=ipax!!a(j);
   end;
 End;

 expand_ipv6: Proc;
 Dcl a(8) Char(4) Var;
 Dcl (s,o1,o2) Char(50) Var Init('');
 Dcl (i,ii,pp,j,n) Bin Fixed(31) Init(0);
 space='IPv6';
 pp=index(ipa,']:');
 If pp>0 Then Do;
   port=substr(ipa,pp+2);
   ipa=substr(ipa,2,pp-2);
   End;
 Else
   Port='';
 s=ipa;
 j=0;
 Do i=1 To 8 While(s>'');
   pp=index(s,':');
   dcl temp Char(6) Var;
   If pp>1 Then
     temp=left(s,pp-1);
   Else
     temp=s;
   temp=right(temp,4,'0');
   Select(pp);
     When(0) Do;
       a(i)=temp;
       s='';
       End;
     When(1) Do;
       a(i)='----';
       ii=i;
       s=substr(s,pp+1);
       If left(s,1)=':' Then
         s=substr(s,2);
       End;
     Otherwise Do;
       a(i)=temp;
       s=substr(s,pp+1);
       End;
     End;
   End;
 n=i-1;
 o1='';
 o2='';
 Do i=1 To n;
   If i=ii Then Do;
     o1=o1!!'----';
     Do j=1 To 9-n;
       o2=o2!!'0000';
       End;
     End;
   Else Do;
     o1=o1!!right(a(i),4,'0');
     o2=o2!!right(a(i),4,'0');
     End;
   End;
  ipax=o2;
 End;

 parse: Proc(s,c,a);
 Dcl s Char(50) Var;
 Dcl c Char( 1);
 Dcl a(*) Char(*) Var;
 Dcl (i,p) Bin Fixed(31);
 a='';
 Do i=1 By 1 While(length(s)>0);
   p=index(s,c);
   If p>0 Then Do;
     a(i)=left(s,p-1);
     s=substr(s,p+1);
     End;
   Else Do;
     a(i)=s;
     s='';
     End;
   End;
  End;

 /*
 underscore: Proc(s) Returns(char(132) Var);
 Dcl s Char(*);
 Dcl r Char(length(s)) Var Init('');
 Dcl i Bin Fixed(31);
 Dcl us Bit(1) Init('0'b);
 Do i=1 To length(s)-1;
   If substr(s,i,1)>' ' Then Do;
     r=r!!'_';
     us='1'b;
     End;
   Else Do;
     If substr(s,i+1,1)>' ' & us Then
       r=r!!'_';
     Else Do;
       r=r!!' ';
       us='0'b;
       End;
     End;
   End;
 If substr(s,length(s),1)>' ' Then
   r=r!!'_';
 Return(r);
 End;

 center: Proc(s,l) Returns(char(50) Var);
 Dcl s char(50) Var;
 Dcl (l,b) Bin Fixed(31);
 b=(l-length(s))/2;
 Return(left(copies(' ',b)!!s,l));
 End;
 */
 copies: Proc(c,n) Returns(char(50) Var);
 Dcl c char(50) Var;
 Dcl n Bin Fixed(31);
 Return(repeat(c,n-1));
 End;


 c2d: Procedure(s) Returns(Char(50) Var);
 Dcl s Char(*) Var;
 Dcl d Pic'99';
 Dcl (v,part,result,old) Char(100) Var;
 Dcl i Bin Fixed(31);
 result='0';
 v='1';

 Do i=length(s) To 1 By -1;
   d=c2d(substr(s,i,1));
   part=longmult((v),(d));
   result=longadd((result),(part));
   v=longmult((v),'16');
   End;
 Do While(left(result,1)='0');
   result=substr(result,2);
   End;
 Return(result);
 /*
 dbg: Proc(txt);
 Dcl txt Char(*);
 Put Skip list(txt);
 End;
 */
 x2d: Procedure(c) Returns(Char(2));
 Dcl c Char(1);
 Dcl res Char(2);
 Select(c);
   When('a','A') res='10';
   When('b','B') res='11';
   When('c','C') res='12';
   When('d','D') res='13';
   When('e','E') res='14';
   When('f','F') res='15';
   Otherwise res='0'!!c;
   End;
 Return(res);
 End;

 longmult: Procedure(as,bs) Returns(Char(1000) Var);
 /* REXX **************************************************************
 * Multiply(as,bs) -> as*bs
 *********************************************************************/
 Dcl (as,bs) Char(*);
 Dcl (a(1000),b(1000),r(1000)) Pic'9';
 Dcl (p,s) Pic'99';
 Dcl (al,bl) Bin Fixed(31);
 Dcl (i,ai,bi,ri,rim) Bin Fixed(31);
 Dcl res Char(1000) Var Init((1000)'0');
 al=length(as); Do ai=al To 1 By -1; a(ai)=substr(as,al-ai+1,1); End;
 bl=length(bs); Do bi=bl To 1 By -1; b(bi)=substr(bs,bl-bi+1,1); End;
 r=0;
 rim=0;
 Do bi=1 To bl;
   Do ai=1 To al;
     ri=ai+bi-1;
     p=a(ai)*b(bi);
     Do i=ri by 1 Until(p=0);
       s=r(i)+p;
       r(i)=mod(s,10);
       p=s/10;
       End;
     rim=max(rim,i);
     End;
   End;
 res='';
 Do i=1 To rim;
   res=r(i)!!res;
   End;
 Return(res);
 End;

 longadd: proc(as,bs) Returns(Char(100) Var);
 Dcl (as,bs) Char(*) Var;
 Dcl cs Char(100) Var Init('');
 Dcl (al,bl,cl,i) Bin Fixed(31);
 Dcl a(100) Pic'9' Init((100)0);
 Dcl b(100) Pic'9' Init((100)0);
 Dcl c(100) Pic'9' Init((100)0);
 Dcl temp Pic'99';
 al=length(as);
 bl=length(bs);
 Do i=1 To al; a(i)=substr(as,al-i+1,1); End;
 Do i=1 To bl; b(i)=substr(bs,bl-i+1,1); End;
 cl=max(al,bl)+1;
 Do i=1 To cl;
   temp=a(i)+b(i)+c(i);
   c(i)=mod(temp,10);
   c(i+1)=c(i+1)+temp/10;
   End;
 Do i=1 To cl;
   cs=c(i)!!cs;
   End;
 Return(cs);
 End;
 End;

 end;

Output:


       input IP address                 hex IP address                    decimal IP address            space  port
______________________________ ________________________________ _______________________________________ _____ _____
127.0.0.1                                                127001                                 1208321  IPv4
127.0.0.1:80                                             127001                                 1208321  IPv4    80
2605:2700:0:3::4713:93e3       260527000000000300000000471393e3  50537416338094019778974086937420469219  IPv6
[2605:2700:0:3::4713:93e3]:80  260527000000000300000000471393e3  50537416338094019778974086937420469219  IPv6    80
::1                            00000000000000000000000000000001                                       1  IPv6
[::1]:80                       00000000000000000000000000000001                                       1  IPv6    80

PowerShell

function Get-IpAddress
{
    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        $InputObject
    )

    Begin
    {
        function Get-Address ([string]$Address)
        {
            if ($Address.IndexOf(".") -ne -1)
            {
                $Address, $port = $Address.Split(":")

                [PSCustomObject]@{
                    IPAddress = [System.Net.IPAddress]$Address
                    Port      = $port
                }
            }
            else
            {
                if ($Address.IndexOf("[") -ne -1)
                {
                    [PSCustomObject]@{
                        IPAddress = [System.Net.IPAddress]$Address
                        Port      = ($Address.Split("]")[-1]).TrimStart(":")
                    }
                }
                else
                {
                    [PSCustomObject]@{
                        IPAddress = [System.Net.IPAddress]$Address
                        Port      = $null
                    }
                }
            }
        }
    }
    Process
    {
        $InputObject | ForEach-Object {
            $address = Get-Address $_
            $bytes = ([System.Net.IPAddress]$address.IPAddress).GetAddressBytes()
            [Array]::Reverse($bytes)
            $i = 0
            $bytes | ForEach-Object -Begin   {[bigint]$decimalIP = 0} `
                                    -Process {$decimalIP += [bigint]$_ * [bigint]::Pow(256, $i); $i++} `
                                    -End     {[PSCustomObject]@{
                                                  Address = $address.IPAddress
                                                  Port    = $address.Port
                                                  Hex     = "0x$($decimalIP.ToString('x'))"}
                                             }
        }
    }
}

Parse an array of IP addresses in a text format:

$ipAddresses = "127.0.0.1","127.0.0.1:80","::1","[::1]:80","2605:2700:0:3::4713:93e3","[2605:2700:0:3::4713:93e3]:80" | Get-IpAddress
$ipAddresses
Output:
Address                  Port Hex                               
-------                  ---- ---                               
127.0.0.1                     0x7f000001                        
127.0.0.1                80   0x7f000001                        
::1                           0x1                               
::1                      80   0x1                               
2605:2700:0:3::4713:93e3      0x260527000000000300000000471393e3
2605:2700:0:3::4713:93e3 80   0x260527000000000300000000471393e3

The Address "property" is an object containing more information...

$ipAddresses[5].Address
Output:
Address            : 
AddressFamily      : InterNetworkV6
ScopeId            : 0
IsIPv6Multicast    : False
IsIPv6LinkLocal    : False
IsIPv6SiteLocal    : False
IsIPv6Teredo       : False
IsIPv4MappedToIPv6 : False
IPAddressToString  : 2605:2700:0:3::4713:93e3

... allowing for specific filtering:

$ipAddresses | where {$_.Address.AddressFamily -eq "InterNetworkV6" -and $_.Port -ne $null}
Output:
Address                  Port Hex                               
-------                  ---- ---                               
::1                      80   0x1                               
2605:2700:0:3::4713:93e3 80   0x260527000000000300000000471393e3

Python

Python: Using ipaddress

Works with: Python version 3.5
from ipaddress import ip_address
from urllib.parse import urlparse

tests = [
    "127.0.0.1",
    "127.0.0.1:80",
    "::1",
    "[::1]:80",
    "::192.168.0.1",
    "2605:2700:0:3::4713:93e3",
    "[2605:2700:0:3::4713:93e3]:80" ]

def parse_ip_port(netloc):
    try:
        ip = ip_address(netloc)
        port = None
    except ValueError:
        parsed = urlparse('//{}'.format(netloc))
        ip = ip_address(parsed.hostname)
        port = parsed.port
    return ip, port

for address in tests:
    ip, port = parse_ip_port(address)
    hex_ip = {4:'{:08X}', 6:'{:032X}'}[ip.version].format(int(ip))
    print("{:39s}  {:>32s}  IPv{}  port={}".format(
        str(ip), hex_ip, ip.version, port ))
Output:
127.0.0.1                                                        7F000001  IPv4  port=None
127.0.0.1                                                        7F000001  IPv4  port=80
::1                                      00000000000000000000000000000001  IPv6  port=None
::1                                      00000000000000000000000000000001  IPv6  port=80
::c0a8:1                                 000000000000000000000000C0A80001  IPv6  port=None
2605:2700:0:3::4713:93e3                 260527000000000300000000471393E3  IPv6  port=None
2605:2700:0:3::4713:93e3                 260527000000000300000000471393E3  IPv6  port=80

Python: Using pyparsing

Library: pyparse

The following uses pyparse to parse the IP address. It's an attempt at using pyparse to describe an IP address in an extended BNF syntax. Using a parser does seems a bit like using a sledgehammer to crack a nut. However it does make for an interesting alternative to using a regular expressions to parse IP addresses. Note - for example - that the parser specifically reports - as an exception - the location where the IP address is syntactically wrong.

import string
from pyparsing import * # import antigravity

tests="""#
127.0.0.1                       # The "localhost" IPv4 address
127.0.0.1:80                    # The "localhost" IPv4 address, with a specified port (80)
::1                             # The "localhost" IPv6 address
[::1]:80                        # The "localhost" IPv6 address, with a specified port (80)
2605:2700:0:3::4713:93e3        # Rosetta Code's primary server's public IPv6 address
[2605:2700:0:3::4713:93e3]:80   # Rosetta Code's primary server's public IPv6 address, +port (80)
2001:db8:85a3:0:0:8a2e:370:7334 # doc, IPv6 for 555-1234
2001:db8:85a3::8a2e:370:7334    # doc
[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443 # doc +port
192.168.0.1                     # private
::ffff:192.168.0.1              # private transitional
::ffff:71.19.147.227            # Rosetta Code's transitional
[::ffff:71.19.147.227]:80       # Rosetta Code's transitional +port
::                              # unspecified
256.0.0.0                       # invalid, octet > 255 (currently not detected)
g::1                            # invalid
0000                                    Bad address
0000:0000                               Bad address
0000:0000:0000:0000:0000:0000:0000:0000 Good address
0000:0000:0000::0000:0000               Good Address
0000::0000::0000:0000                   Bad address
ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff Good address
ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff Bad address
fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff  Good address
fff:ffff:0:ffff:ffff:ffff:ffff:ffff     Good address
"""

def print_args(args):
  print "print_args:", args

def join(args):
  args[0]="".join(args)
  del args[1:]

def replace(val):
  def lambda_replace(args):
    args[0]=val
    del args[1:]
  return lambda_replace

def atoi(args): args[0]=string.atoi(args[0])
def itohex2(args): args[0]="%02x"%args[0]

def hextoi(args): args[0]=string.atoi(args[0], 16)
def itohex4(args): args[0]="%04x"%args[0]

def assert_in_range(lwb, upb):
  def range_check(args):
    return # turn range checking off
    if args[0] < lwb:
      raise ValueError,"value %d < %d"%(args[0], lwb)
    if args[0] > upb:
      raise ValueError,"value %d > %d"%(args[0], upb)
  return range_check

dot = Literal(".").suppress()("dot"); colon = Literal(":").suppress()("colon")
octet = Word(nums).setParseAction(atoi,assert_in_range(0,255),itohex2)("octet");

port = Word(nums).setParseAction(atoi,assert_in_range(0,256*256-1))("port")
ipv4 = (octet + (dot+octet)*3)("addr")
ipv4.setParseAction(join) #,hextoi)

ipv4_port = ipv4+colon.suppress()+port

a2f = "abcdef"
hex = oneOf(" ".join(nums+a2f));

hexet = (hex*(0,4))("hexet")
hexet.setParseAction(join, hextoi, itohex4)

max=8; stop=max+1

xXXXX_etc = [None, hexet]; xXXXX_etc.extend([hexet + (colon+hexet)*n for n in range(1,max)])
x0000_etc = [ Literal("::").setParseAction(replace("0000"*num_x0000s)) for num_x0000s in range(stop) ]

ipv6=xXXXX_etc[-1]+x0000_etc[0] | xXXXX_etc[-1]

# Build a table of rules for IPv6, in particular the double colon
for num_prefix in range(max-1, -1, -1):
  for num_x0000s in range(0,stop-num_prefix):
    x0000 = x0000_etc[num_x0000s]
    num_suffix=max-num_prefix-num_x0000s
    if num_prefix:
      if num_suffix: pat = xXXXX_etc[num_prefix]+x0000+xXXXX_etc[num_suffix]
      else:          pat = xXXXX_etc[num_prefix]+x0000
    elif num_suffix: pat =                       x0000+xXXXX_etc[num_suffix]
    else: pat=x0000
    ipv6 = ipv6 | pat

ipv6.setParseAction(join) # ,hextoi)
ipv6_port = Literal("[").suppress() + ipv6 + Literal("]").suppress()+colon+port

ipv6_transitional = (Literal("::ffff:").setParseAction(replace("0"*20+"ffff"))+ipv4).setParseAction(join)
ipv6_transitional_port = Literal("[").suppress() + ipv6_transitional + Literal("]").suppress()+colon+port

ip_fmt = (
           (ipv4_port|ipv4)("ipv4") |
           (ipv6_transitional_port|ipv6_transitional|ipv6_port|ipv6)("ipv6")
         ) + LineEnd()

class IPAddr(object):
  def __init__(self, string):
    self.service = dict(zip(("address","port"), ip_fmt.parseString(string)[:]))
  def __getitem__(self, key): return self.service[key]
  def __contains__(self, key): return key in self.service
  def __repr__(self): return `self.service` # "".join(self.service)
  address=property(lambda self: self.service["address"])
  port=property(lambda self: self.service["port"])
  is_service=property(lambda self: "port" in self.service)
  version=property(lambda self: {False:4, True:6}[len(self.address)>8])

for test in tests.splitlines():
  if not test.startswith("#"):
    ip_str, desc = test.split(None,1)
    print ip_str,"=>",
    try:
      ip=IPAddr(ip_str)
      print ip, "IP Version:",ip.version,"- Address is OK!",
    except (ParseException,ValueError), details: print "Bad! IP address syntax error detected:",details,
    print "- Actually:",desc

Output:

127.0.0.1 => {'address': '7f000001'} IP Version: 4 - Address is OK! - Actually: # The "localhost" IPv4 address
127.0.0.1:80 => {'port': 80, 'address': '7f000001'} IP Version: 4 - Address is OK! - Actually: # The "localhost" IPv4 address, with a specifie
d port (80)
::1 => {'address': '00000000000000000000000000000001'} IP Version: 6 - Address is OK! - Actually: # The "localhost" IPv6 address
[::1]:80 => {'port': 80, 'address': '00000000000000000000000000000001'} IP Version: 6 - Address is OK! - Actually: # The "localhost" IPv6 addr
ess, with a specified port (80)
2605:2700:0:3::4713:93e3 => {'address': '260527000000000300000000471393e3'} IP Version: 6 - Address is OK! - Actually: # Rosetta Code's primar
y server's public IPv6 address
[2605:2700:0:3::4713:93e3]:80 => {'port': 80, 'address': '260527000000000300000000471393e3'} IP Version: 6 - Address is OK! - Actually: # Rose
tta Code's primary server's public IPv6 address, +port (80)
2001:db8:85a3:0:0:8a2e:370:7334 => {'address': '20010db885a3000000008a2e03707334'} IP Version: 6 - Address is OK! - Actually: # doc, IPv6 for 
555-1234
2001:db8:85a3::8a2e:370:7334 => {'address': '20010db885a3000000008a2e03707334'} IP Version: 6 - Address is OK! - Actually: # doc
[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443 => {'port': 443, 'address': '20010db885a308d313198a2e03707348'} IP Version: 6 - Address is OK! - Ac
tually: # doc +port
192.168.0.1 => {'address': 'c0a80001'} IP Version: 4 - Address is OK! - Actually: # private
::ffff:192.168.0.1 => {'address': '00000000000000000000ffffc0a80001'} IP Version: 6 - Address is OK! - Actually: # private transitional
::ffff:71.19.147.227 => {'address': '00000000000000000000ffff471393e3'} IP Version: 6 - Address is OK! - Actually: # Rosetta Code's transition
al
[::ffff:71.19.147.227]:80 => {'port': 80, 'address': '00000000000000000000ffff471393e3'} IP Version: 6 - Address is OK! - Actually: # Rosetta 
Code's transitional +port
:: => {'address': '00000000000000000000000000000000'} IP Version: 6 - Address is OK! - Actually: # unspecified
256.0.0.0 => {'address': '100000000'} IP Version: 6 - Address is OK! - Actually: # invalid, octet > 255 (currently not detected)
g::1 => Bad! IP address syntax error detected:  (at char 4), (line:1, col:5) - Actually: # invalid
0000 => Bad! IP address syntax error detected: Expected "." (at char 4), (line:1, col:5) - Actually: Bad address
0000:0000 => Bad! IP address syntax error detected: Expected ":" (at char 9), (line:1, col:10) - Actually: Bad address
0000:0000:0000:0000:0000:0000:0000:0000 => {'address': '00000000000000000000000000000000'} IP Version: 6 - Address is OK! - Actually: Good add
ress
0000:0000:0000::0000:0000 => {'address': '00000000000000000000000000000000'} IP Version: 6 - Address is OK! - Actually: Good Address
0000::0000::0000:0000 => Bad! IP address syntax error detected: Expected end of line (at char 10), (line:1, col:11) - Actually: Bad address
ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff => {'address': 'ffffffffffffffffffffffffffffffff'} IP Version: 6 - Address is OK! - Actually: Good add
ress
ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff => Bad! IP address syntax error detected: Expected ":" (at char 18), (line:1, col:19) - Actually: Bad 
address
fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff => {'address': '0fffffffffffffffffffffffffffffff'} IP Version: 6 - Address is OK! - Actually: Good addr
ess
fff:ffff:0:ffff:ffff:ffff:ffff:ffff => {'address': '0fffffff0000ffffffffffffffffffff'} IP Version: 6 - Address is OK! - Actually: Good address

Racket

#lang racket

(require net/private/ip)

(define (bytes->hex bs)
  (string-append* (map (λ(n) (~r n #:base 16 #:min-width 2 #:pad-string "0"))
                       (bytes->list bs))))

(define (parse-ip str)
  (define-values [ipstr portstr]
    (match str
      [(regexp #rx"^([0-9.]+):([0-9]+)$" (list _ i p)) (values i p)]
      [(regexp #rx"^\\[([0-9a-fA-F:]+)\\]:([0-9]+)$" (list _ i p)) (values i p)]
      [_ (values str "")]))
  (define ip (make-ip-address ipstr))
  (define 4? (ipv4? ip))
  (define hex (bytes->hex ((if 4? ipv4-bytes ipv6-bytes) ip)))
  (displayln (~a (~a str #:min-width 30)
                 " "
                 (~a hex #:min-width 32 #:align 'right)
                 " ipv" (if 4? "4" "6") " " portstr)))

(for-each parse-ip
          '("127.0.0.1"
            "127.0.0.1:80"
            "::1"
            "[::1]:80"
            "2605:2700:0:3::4713:93e3"
            "[2605:2700:0:3::4713:93e3]:80"))
Output:
127.0.0.1                                              7f000001 ipv4 
127.0.0.1:80                                           7f000001 ipv4 80
::1                            00000000000000000000000000000001 ipv6 
[::1]:80                       00000000000000000000000000000001 ipv6 80
2605:2700:0:3::4713:93e3       260527000000000300000000471393e3 ipv6 
[2605:2700:0:3::4713:93e3]:80  260527000000000300000000471393e3 ipv6 80

Raku

(formerly Perl 6)

grammar IP_Addr {
    token TOP { ^ [ <IPv4> | <IPv6> ] $ }
 
    token IPv4 {
        [ <d8> +% '.' ] <?{ $<d8> == 4 }> <port>?
                { @*by8 = @$<d8> }
    }

    token IPv6 {
        |     <ipv6>
        | '[' <ipv6> ']' <port>
    }

    token ipv6 {
        | <h16> +% ':' <?{ $<h16> == 8 }>
                { @*by16 = @$<h16> }
 
        | [ (<h16>) +% ':']? '::' [ (<h16>) +% ':' ]? <?{ @$0 + @$18 }>
                { @*by16 = |@$0, |('0' xx 8 - (@$0 + @$1)), |@$1 }
 
        | '::ffff:' <IPv4>
                { @*by16 = |('0' xx 5), 'ffff', |(by8to16 @*by8) }
    }

    token d8  { (\d+) <?{ $0 < 256   }> }
    token d16 { (\d+) <?{ $0 < 65536 }> }
    token h16 { (<xdigit>+) <?{ $0.chars4 }> }

    token port {
        ':' <d16> { $*port = +$<d16> }
    }
}

sub by8to16 (@m) { gather for @m -> $a,$b { take ($a * 256 + $b).fmt("%04x") } }

my @cases = <
    127.0.0.1
    127.0.0.1:80
    ::1
    [::1]:80
    2605:2700:0:3::4713:93e3
    [2605:2700:0:3::4713:93e3]:80
    2001:db8:85a3:0:0:8a2e:370:7334
    2001:db8:85a3::8a2e:370:7334
    [2001:db8:85a3:8d3:1319:8a2e:370:7348]:443
    192.168.0.1
    ::ffff:192.168.0.1
    ::ffff:71.19.147.227
    [::ffff:71.19.147.227]:80
    ::
    256.0.0.0
    g::1
    0000
    0000:0000
    0000:0000:0000:0000:0000:0000:0000:0000
    0000:0000:0000::0000:0000
    0000::0000::0000:0000
    ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
    ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff
    fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
    fff:ffff:0:ffff:ffff:ffff:ffff:ffff
>;

for @cases -> $addr {
    my @*by8;
    my @*by16;
    my $*port;

    IP_Addr.parse($addr);

    say $addr;
    if @*by16 {
        say "  IPv6: ", @*by16.map({:16(~$_)})».fmt("%04x").join;
        say "  Port: ", $*port if $*port;
    }
    elsif @*by8 {
        say "  IPv4: ", @*by8».fmt("%02x").join;
        say "  Port: ", $*port if $*port;
    }
    else {
        say "  BOGUS!";
    }
    say '';
}
Output:
127.0.0.1
  IPv4: 7f000001

127.0.0.1:80
  IPv4: 7f000001
  Port: 80

::1
  IPv6: 00000000000000000000000000000001

[::1]:80
  IPv6: 00000000000000000000000000000001
  Port: 80

2605:2700:0:3::4713:93e3
  IPv6: 260527000000000300000000471393e3

[2605:2700:0:3::4713:93e3]:80
  IPv6: 260527000000000300000000471393e3
  Port: 80

2001:db8:85a3:0:0:8a2e:370:7334
  IPv6: 20010db885a3000000008a2e03707334

2001:db8:85a3::8a2e:370:7334
  IPv6: 20010db885a3000000008a2e03707334

[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443
  IPv6: 20010db885a308d313198a2e03707348
  Port: 443

192.168.0.1
  IPv4: c0a80001

::ffff:192.168.0.1
  IPv6: 00000000000000000000ffffc0a80001

::ffff:71.19.147.227
  IPv6: 00000000000000000000ffff471393e3

[::ffff:71.19.147.227]:80
  IPv6: 00000000000000000000ffff471393e3
  Port: 80

::
  IPv6: 00000000000000000000000000000000

256.0.0.0
  BOGUS!

g::1
  BOGUS!

0000
  BOGUS!

0000:0000
  BOGUS!

0000:0000:0000:0000:0000:0000:0000:0000
  IPv6: 00000000000000000000000000000000

0000:0000:0000::0000:0000
  IPv6: 00000000000000000000000000000000

0000::0000::0000:0000
  IPv6: 00000000000000000000000000000000

ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
  IPv6: ffffffffffffffffffffffffffffffff

ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff
  BOGUS!

fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
  IPv6: 0fffffffffffffffffffffffffffffff

fff:ffff:0:ffff:ffff:ffff:ffff:ffff
  IPv6: 0fffffff0000ffffffffffffffffffff

REXX

One of REXX's strongest features is its ability for parsing,   it has the   parse   instruction for this purpose.

version 1

/*REXX program parses an  IP address  into  ──►  IPv4  or  IPv6 format,  optional pport.*/
_= "_";    say center('input IP address'   , 30),
               center('hex IP address'     , 32),
               center('decimal IP address' , 39)         "space  port"
           say copies(_, 30)   copies(_, 32)   copies(_, 39)   copies(_, 5)   copies(_, 5)
call IP_parse  127.0.0.1                         /*this simple  IP  doesn't need quotes.*/
call IP_parse '127.0.0.1:80'
call IP_parse '::1'
call IP_parse '[::1]:80'
call IP_parse '2605:2700:0:3::4713:93e3'
call IP_parse '[2605:2700:0:3::4713:93e3]:80'
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
IP_parse:  procedure;  parse arg a .;       hx=;              @.=;       numeric digits 50
           dot= pos(., a)\==0                    /*see if there is a dot present in IP. */

           if dot then do;   parse var   a    @.1  '.'  @.2  "."  @.3  '.'  @.4  ":"  port
                                            do j=1  for 4;    hx= hx  ||  d2x(@.j, 2)
                                            end   /*j*/
                       end
                  else do;   parse var  a  pureA  ']:'  port
                       _= space( translate( pureA, , '[]'), 0)        /*remove brackets.*/
                       parse var _ x '::' y
                                            do L=1  until x==''       /*get  left side. */
                                            parse var  x  @.L  ':'  x
                                            end   /*L*/
                       y= reverse(y)
                                            do r=8  by -1             /*get right side. */
                                            parse var  y  z  ':'  y;   if z=='' then leave
                                            @.r= reverse(z)
                                            end   /*r*/

                            do k=1  for 8;  hx=hx  ||  right( word(@.k 0, 1), 4, 0)
                            end   /*k*/
                       end

           say left(a,30) right(hx,32) right(x2d(hx),39) ' IPv' || (6-2*dot) right(port,5)
           return
output   when using the internal default input:
       input IP address                 hex IP address                    decimal IP address            space  port
────────────────────────────── ──────────────────────────────── ─────────────────────────────────────── ───── ─────
127.0.0.1                                              7F000001                              2130706433  IPv4
127.0.0.1:80                                           7F000001                              2130706433  IPv4    80
::1                            00000000000000000000000000000001                                       1  IPv6
[::1]:80                       00000000000000000000000000000001                                       1  IPv6    80
2605:2700:0:3::4713:93e3       260527000000000300000000471393e3  50537416338094019778974086937420469219  IPv6
[2605:2700:0:3::4713:93e3]:80  260527000000000300000000471393e3  50537416338094019778974086937420469219  IPv6    80

version 2

/* REXX ***************************************************************
* 27.05.2013 Walter Pachl
**********************************************************************/
Numeric Digits 100
say center('input IP address'   ,30),
    center('hex IP address'     ,32),
    center('decimal IP address' ,39)         'space  port'

say copies(_,30) copies(_,32) copies(_,39) copies(_,5) copies(_,5) /*hdr*/
call expand '127.0.0.1'
call expand '127.0.0.1:80'
call expand '::1'
call expand '[::1]:80'
call expand '2605:2700:0:3::4713:93e3'
call expand '[2605:2700:0:3::4713:93e3]:80'
Say ' '
Say 'The following 2 are the same'
Call expand '2001:0db8:0:0:0:0:1428:57ab'
Call expand '2001:db8::1428:57ab'
Say ' '
Say 'The following 3 are all the same'
Call expand '2001:0db8:0:0:8d3:0:0:0'
Call expand '2001:db8:0:0:8d3::'
Call expand '2001:db8::8d3:0:0:0'
Exit

expand: Procedure
Parse Arg s
If pos('.',s)>0 Then
  Parse Value expand_ip4(s) With exp space port
Else
  Parse Value expand_ip6(s) With exp space port
Say left(s,30) right(exp,32) right(x2d(exp),39) right(space,5) right(port,5)
Return

expand_ip4: Procedure
Parse Arg s
If pos(':',s)>0 Then
  Parse Var s s ':' port
Else
  port=''
Do i=1 To 4
  Parse Var s a.i '.' s
  End
res=''
Do i=1 To 4
  res=res||d2x(a.i,2)
  End
Return res 'IPv4' port

expand_ip6: Procedure
/**********************************************************************
* Note: Doublecolon ('::') requires the inclusion of as many 0000
* tokens as necessary to result in 8 tokens
**********************************************************************/
Parse Arg s
If pos(']:',s)>0 Then
  Parse Var s '[' s ']:' port
Else
  port=''
sc=s
ii=0
Do i=1 To 8 While s<>''
  Parse Var s x.i ':' s
  If left(s,1)=':' Then Do
    ii=i
    s=substr(s,2)
    End
  End
n=i-1
ol=''
o2=''
Do i=1 To n
  ol=ol||right(x.i,4,'0')
  o2=o2||right(x.i,4,'0')
  If i=ii Then Do
    ol=ol||'----'
    Do j=1 To 8-n
      o2=o2||'0000'
      End
    End
  End
Return o2 'IPv6' port

Output:


       input IP address                 hex IP address                    decimal IP address            space  port
______________________________ ________________________________ _______________________________________ _____ _____
127.0.0.1                                              7F000001                              2130706433  IPv4
127.0.0.1:80                                           7F000001                              2130706433  IPv4    80
::1                            00000000000000000000000000000001                                       1  IPv6
[::1]:80                       00000000000000000000000000000001                                       1  IPv6    80
2605:2700:0:3::4713:93e3       260527000000000300000000471393e3  50537416338094019778974086937420469219  IPv6
[2605:2700:0:3::4713:93e3]:80  260527000000000300000000471393e3  50537416338094019778974086937420469219  IPv6    80

The following 2 are the same
2001:0db8:0:0:0:0:1428:57ab    20010db80000000000000000142857ab  42540766411282592856903984951992014763  IPv6
2001:db8::1428:57ab            20010db80000000000000000142857ab  42540766411282592856903984951992014763  IPv6

The following 3 are all the same
2001:0db8:0:0:8d3:0:0:0        20010db80000000008d3000000000000  42540766411282592857539836924043198464  IPv6
2001:db8:0:0:8d3::             20010db80000000008d3000000000000  42540766411282592857539836924043198464  IPv6
2001:db8::8d3:0:0:0            20010db80000000008d3000000000000  42540766411282592857539836924043198464  IPv6

Ruby

require 'ipaddr'

 
TESTCASES = ["127.0.0.1",                "127.0.0.1:80",
                "::1",                      "[::1]:80",
                "2605:2700:0:3::4713:93e3", "[2605:2700:0:3::4713:93e3]:80"]                            

output = [%w(String Address Port Family Hex),
          %w(------ ------- ---- ------ ---)]

def output_table(rows)
  widths = []
  rows.each {|row| row.each_with_index {|col, i| widths[i] = [widths[i].to_i, col.to_s.length].max }}
  format = widths.map {|size| "%#{size}s"}.join("\t")
  rows.each {|row| puts format % row}
end

TESTCASES.each do |str|
  case str  # handle port; IPAddr does not.
  when /\A\[(?<address> .* )\]:(?<port> \d+ )\z/x      # string like "[::1]:80"
    address, port = $~[:address], $~[:port]
  when /\A(?<address> [^:]+ ):(?<port> \d+ )\z/x       # string like "127.0.0.1:80"
    address, port = $~[:address], $~[:port]
  else                                                 # string with no port number
    address, port = str, nil
  end
  
  ip_addr = IPAddr.new(address) 
  family = "IPv4" if ip_addr.ipv4?
  family = "IPv6" if ip_addr.ipv6?

  output << [str, ip_addr.to_s, port.to_s, family, ip_addr.to_i.to_s(16)]
end

output_table(output)
Output:
                       String                   Address    Port    Family                               Hex
                       ------                    -------    ----    ------                               ---
                    127.0.0.1                  127.0.0.1              IPv4                          7f000001
                 127.0.0.1:80                  127.0.0.1      80      IPv4                          7f000001
                          ::1                        ::1              IPv6                                 1
                     [::1]:80                        ::1      80      IPv6                                 1
     2605:2700:0:3::4713:93e3   2605:2700:0:3::4713:93e3              IPv6  260527000000000300000000471393e3
[2605:2700:0:3::4713:93e3]:80   2605:2700:0:3::4713:93e3      80      IPv6  260527000000000300000000471393e3

Rust

use std::{
    net::{IpAddr, SocketAddr},
    str::FromStr,
};

#[derive(Clone, Debug)]
struct Addr {
    addr: IpAddr,
    port: Option<u16>,
}

impl std::fmt::Display for Addr {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let ipv = if self.addr.is_ipv4() { "4" } else { "6" };

        let hex = match self.addr {
            IpAddr::V4(addr) => u32::from(addr) as u128,
            IpAddr::V6(addr) => u128::from(addr),
        };

        match self.port {
            Some(p) => write!(
                f,
                "address: {}, port: {}, hex: {:x} (IPv{})",
                self.addr, p, hex, ipv
            ),

            None => write!(
                f,
                "address: {}, port: N/A, hex: {:x} (IPv{}) ",
                self.addr, hex, ipv
            ),
        }
    }
}

impl FromStr for Addr {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if let Ok(addr) = s.parse::<IpAddr>() {
            Ok(Self { addr, port: None })
        } else if let Ok(sock) = s.parse::<SocketAddr>() {
            Ok(Self {
                addr: sock.ip(),
                port: Some(sock.port()),
            })
        } else {
            Err(())
        }
    }
}

fn print_addr(s: &str) {
    match s.parse::<Addr>() {
        Ok(addr) => println!("{}: {}", s, addr),
        _ => println!("{} not a valid address", s),
    }
}

fn main() {
    [
        "127.0.0.1",
        "127.0.0.1:80",
        "::1",
        "[::1]:80",
        "2605:2700:0:3::4713:93e3",
        "[2605:2700:0:3::4713:93e3]:80",
    ]
    .iter()
    .cloned()
    .for_each(print_addr);
}

Scala

Full blown ultimate solution

Output:

Best seen running in your browser Scastie (remote JVM).

object IPparser extends App {

  /*
  Parse an IP (v4/v6) Address

  This software can parse all ipv4/ipv6 address text representations
  of IP Address in common usage against the IEF RFC 5952 specification.

  The results of the parse are:
  - The parts of the text are valid representations. This is indicated in the list by a ✔ or ✘.
  - The intended version; 4 or 6.
  - Compliance with RFC 5952 in respect with double colons Compressed zeroes expansion ('::') and lower case letters.
  - Hexadecimal representation of the intended IP address.
  - If part in the text the port number which is optional.
  - The used text string search pattern.

  As much of the information is produced if there are invalid parts in the remark field.
  */

  def myCases = Map(
    "http:"                                      -> IPInvalidAddressComponents(remark = "No match at all: 'http:'."),
    "http://"                                    -> IPInvalidAddressComponents(remark = "No match at all: 'http://'."),
    "http:// "                                   -> IPInvalidAddressComponents(remark = "No match at all: 'http:// '."),
    "http://127.0.0.1/"                          -> ResultContainer(4, BigInt("7F000001", 16)),
    "http://127.0.0.1:80/"                       -> ResultContainer(4, BigInt("7F000001", 16), Some(80)),
    "http://127.0.0.1:65536" ->
      IPInvalidAddressComponents(4, BigInt("7F000001", 16), Some(65536), remark = "Port number out of range."),
    "http://192.168.0.1"                         -> ResultContainer(4, BigInt("C0A80001", 16)),
    "http:/1::"                                  -> ResultContainer(6, BigInt("10000000000000000000000000000", 16)),
    "http:/2001:0db8:0:0:0:0:1428:57ab/"         -> ResultContainer(6, BigInt("20010db80000000000000000142857ab", 16)),
    "2001:0db8:0:0:8d3:0:0:0"                    -> ResultContainer(6, BigInt("20010db80000000008d3000000000000", 16)),
    "2001:db8:0:0:8d3::"                         -> ResultContainer(6, BigInt("20010db80000000008d3000000000000", 16)),
    "http:/2001:db8:3:4::192.0.2.33"                   -> ResultContainer(6, BigInt("20010db80003000400000000c0000221", 16)),
    "2001:db8:85a3:0:0:8a2e:370:7334"            -> ResultContainer(6, BigInt("20010db885a3000000008a2e03707334", 16)),
    "2001:db8::1428:57ab"                        -> ResultContainer(6, BigInt("20010db80000000000000000142857ab", 16)),
    "2001:db8::8d3:0:0:0"                        -> ResultContainer(6, BigInt("20010db80000000008d3000000000000", 16)),
    "256.0.0.0"                                  -> IPInvalidAddressComponents(4, remark = "Invalid octets."),
    "2605:2700:0:3::4713:93e3"                   -> ResultContainer(6, BigInt("260527000000000300000000471393e3", 16)),
    "::"                                         -> ResultContainer(6, BigInt("00000000000000000000000000000000", 16)),
    "1::8"                                       -> ResultContainer(6, BigInt("00010000000000000000000000000008", 16)),
    "::1"                                        -> ResultContainer(6, BigInt("00000000000000000000000000000001", 16)),
    "::192.168.0.1"                              -> ResultContainer(6, BigInt("000000000000000000000000c0a80001", 16)),
    "::255.255.255.255"                          -> ResultContainer(6, BigInt("000000000000000000000000ffffffff", 16)),
    "http:/[::255.255.255.255]:65536" ->
      IPInvalidAddressComponents(6, BigInt("000000000000000000000000ffffffff", 16), Some(65536), remark = "Port number out of range."),
    "::2:3:4:5:6:7:8"                            -> ResultContainer(6, BigInt("00000002000300040005000600070008", 16), strictRFC5952 = false),
    "::8"                                        -> ResultContainer(6, BigInt("00000000000000000000000000000008", 16)),
    "::c0a8:1"                                   -> ResultContainer(6, BigInt("000000000000000000000000c0a80001", 16)),
    "::ffff:0:255.255.255.255"                   -> ResultContainer(6, BigInt("0000000000000000ffff0000ffffffff", 16)),
    "::ffff:127.0.0.0.1"                         -> IPInvalidAddressComponents(4, remark = "Address puntation error: ':127.0.0.0.1'."),
    "::ffff:127.0.0.1"                           -> ResultContainer(6, BigInt("00000000000000000000ffff7f000001", 16)),
    "::ffff:192.168.0.1"                         -> ResultContainer(6, BigInt("00000000000000000000ffffc0a80001", 16)),
    "::ffff:192.168.173.22"                      -> ResultContainer(6, BigInt("00000000000000000000ffffc0a8ad16", 16)),
    "::ffff:255.255.255.255"                     -> ResultContainer(6, BigInt("00000000000000000000ffffffffffff", 16)),
    "::ffff:71.19.147.227"                       -> ResultContainer(6, BigInt("00000000000000000000ffff471393e3", 16)),
    "1:2:3:4:5:6:7::"                            -> ResultContainer(6, BigInt("00010002000300040005000600070000", 16), strictRFC5952 = false),
    "8000:2:3:4:5:6:7::"                         -> ResultContainer(6, BigInt("80000002000300040005000600070000", 16), strictRFC5952 = false),
    "1:2:3:4:5:6::8"                             -> ResultContainer(6, BigInt("00010002000300040005000600000008", 16), strictRFC5952 = false),
    "1:2:3:4:5::8"                               -> ResultContainer(6, BigInt("00010002000300040005000000000008", 16)),
    "1::7:8"                                     -> ResultContainer(6, BigInt("00010000000000000000000000070008", 16)),
    "a::b::1"                                    -> IPInvalidAddressComponents(remark = "Noise found: 'a::b::1'."),
    "fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"     -> ResultContainer(6, BigInt("0fffffffffffffffffffffffffffffff", 16)),
    "FFFF:ffff:ffff:ffff:ffff:ffff:ffff:ffff"    -> ResultContainer(6, BigInt("ffffffffffffffffffffffffffffffff", 16), strictRFC5952 = false),
    "ffff:ffff:ffff:fffg:ffff:ffff:ffff:ffff"    -> IPInvalidAddressComponents(remark = "No match at all: 'ffff:ffff:ffff:fffg…'."),
    "g::1"                                       -> IPInvalidAddressComponents(6, remark ="Invalid input 'g::1'."),
    "[g::1]:192.0.2.33"                          -> IPInvalidAddressComponents(4, remark = "Address puntation error: ':192.0.2.33'."),
    "1:2:3:4:5:6:7:8"                            -> ResultContainer(6, BigInt("00010002000300040005000600070008", 16)),
    "1:2:3:4:5::7:8"                             -> ResultContainer(6, BigInt("00010002000300040005000000070008", 16), strictRFC5952 = false),
    "1:2:3:4::6:7:8"                             -> ResultContainer(6, BigInt("00010002000300040000000600070008", 16), strictRFC5952 = false),
    "1:2:3:4::8"                                 -> ResultContainer(6, BigInt("00010002000300040000000000000008", 16)),
    "1:2:3::5:6:7:8"                             -> ResultContainer(6, BigInt("00010002000300000005000600070008", 16), strictRFC5952 = false),
    "1:2:3::8"                                   -> ResultContainer(6, BigInt("00010002000300000000000000000008", 16)),
    "1:2::4:5:6:7:8"                             -> ResultContainer(6, BigInt("00010002000000040005000600070008", 16), strictRFC5952 = false),
    "1:2::8"                                     -> ResultContainer(6, BigInt("00010002000000000000000000000008", 16)),
    "1::3:4:5:6:7:8"                             -> ResultContainer(6, BigInt("00010000000300040005000600070008", 16), strictRFC5952 = false),
    "1::4:5:6:7:8"                               -> ResultContainer(6, BigInt("00010000000000040005000600070008", 16)),
    "1::5:6:7:8"                                 -> ResultContainer(6, BigInt("00010000000000000005000600070008", 16)),
    "[1::6:7:8]"                                 -> ResultContainer(6, BigInt("0010000000000000000000600070008", 16)),
    "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"    -> ResultContainer(6, BigInt("ffffffffffffffffffffffffffffffff", 16)),
    "64:ff9b::192.0.2.33"                        -> ResultContainer(6, BigInt("0064ff9b0000000000000000c0000221", 16)),
    "64:ff9b::256.0.2.33" ->
      IPInvalidAddressComponents(6, BigInt("0064ff9b000000000000000000000000", 16), remark = "Invalid octets."),
    "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443" -> ResultContainer(6, BigInt("20010db885a308d313198a2e03707348", 16), Some(443)),
    "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:100000" ->
      IPInvalidAddressComponents(6, BigInt("20010db885a308d313198a2e03707348", 16), Some(100000), remark = "Port number out of range."),
    "[2605:2700:0:3::4713:93e3]:80"              -> ResultContainer(6, BigInt("260527000000000300000000471393e3", 16), Some(80)),
    "[::ffff:192.168.0.1]:22"                    -> ResultContainer(6, BigInt("00000000000000000000ffffc0a80001", 16), Some(22)),
    "[::ffff:192.168.173.22]:80"                 -> ResultContainer(6, BigInt("00000000000000000000ffffc0a8ad16", 16), Some(80)),
    "[::ffff:71.19.147.227]:80"                  -> ResultContainer(6, BigInt("00000000000000000000FFFF471393E3", 16), Some(80)),
    "2001:0DB8:0:0:0:0:1428:57AB"                -> ResultContainer(6, BigInt("20010DB80000000000000000142857AB", 16), strictRFC5952 = false),
    "2001:0DB8:0:0:8D3:0:0:0"                    -> ResultContainer(6, BigInt("20010DB80000000008D3000000000000", 16), strictRFC5952 = false),
    "2001:DB8:0:0:8D3::"                         -> ResultContainer(6, BigInt("20010DB80000000008D3000000000000", 16), strictRFC5952 = false),
    "2001:DB8:3:4::192.0.2.33"                   -> ResultContainer(6, BigInt("20010DB80003000400000000C0000221", 16), strictRFC5952 = false),
    "2001:DB8:85A3:0:0:8A2E:370:7334"            -> ResultContainer(6, BigInt("20010DB885A3000000008A2E03707334", 16), strictRFC5952 = false),
    "2001:DB8::1428:57AB"                        -> ResultContainer(6, BigInt("20010DB80000000000000000142857AB", 16), strictRFC5952 = false),
    "2001:DB8::8D3:0:0:0"                        -> ResultContainer(6, BigInt("20010DB80000000008D3000000000000", 16), strictRFC5952 = false),
    "2605:2700:0:3::4713:93E3"                   -> ResultContainer(6, BigInt("260527000000000300000000471393E3", 16), strictRFC5952 = false),
    "::192.168.0.1"                              -> ResultContainer(6, BigInt("000000000000000000000000C0A80001", 16)),
    "::255.255.255.255"                          -> ResultContainer(6, BigInt("000000000000000000000000FFFFFFFF", 16)),
    "::C0A8:1"                                   -> ResultContainer(6, BigInt("000000000000000000000000c0a80001", 16), strictRFC5952 = false),
    "::FFFF:0:255.255.255.255"                   -> ResultContainer(6, BigInt("0000000000000000FFFF0000FFFFFFFF", 16), strictRFC5952 = false),
    "::FFFF:127.0.0.0.1"                         -> IPInvalidAddressComponents(4, remark = "Address puntation error: ':127.0.0.0.1'."),
    "::FFFF:127.0.0.1"                           -> ResultContainer(6, BigInt("00000000000000000000FFFF7F000001", 16), strictRFC5952 = false),
    "::FFFF:192.168.0.1"                         -> ResultContainer(6, BigInt("00000000000000000000FFFFC0A80001", 16), strictRFC5952 = false),
    "::FFFF:192.168.173.22"                      -> ResultContainer(6, BigInt("00000000000000000000FFFFC0A8AD16", 16), strictRFC5952 = false),
    "::FFFF:255.255.255.255"                     -> ResultContainer(6, BigInt("00000000000000000000FFFFFFFFFFFF", 16), strictRFC5952 = false),
    "::FFFF:71.19.147.227"                       -> ResultContainer(6, BigInt("00000000000000000000FFFF471393E3", 16), strictRFC5952 = false),
    "[1::]:80"                                   -> ResultContainer(6, BigInt("00010000000000000000000000000000", 16), Some(80)),
    "[2001:DB8:85A3:8D3:1319:8A2E:370:7348]:443" -> ResultContainer(6, BigInt("20010db885a308d313198a2e03707348", 16), Some(443), strictRFC5952 = false),
    "[2605:2700:0:3::4713:93E3]:80"              -> ResultContainer(6, BigInt("260527000000000300000000471393e3", 16), Some(80), strictRFC5952 = false),
    "[::1]:80"                                   -> ResultContainer(6, BigInt("00000000000000000000000000000001", 16), Some(80)),
    "[::1]:65536" ->
      IPInvalidAddressComponents(6, BigInt("00000000000000000000000000000001", 16), Some(65536), remark = "Port number out of range."),
    "[::]:80"                                    -> ResultContainer(6, BigInt("00000000000000000000000000000000", 16), Some(80)),
    "[::FFFF:192.168.0.1]:22"                    -> ResultContainer(6, BigInt("00000000000000000000ffffc0a80001", 16), Some(22), strictRFC5952 = false),
    "[::FFFF:192.168.173.22]:80"                 -> ResultContainer(6, BigInt("00000000000000000000ffffc0a8ad16", 16), Some(80), strictRFC5952 = false),
    "[::FFFF:71.19.147.227]:80"                  -> ResultContainer(6, BigInt("00000000000000000000ffff471393e3", 16), Some(80), strictRFC5952 = false),
    "A::B::1"                                    -> IPInvalidAddressComponents(remark = "Noise found: 'A::B::1'."),
    "FFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"     -> ResultContainer(6, BigInt("0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16), strictRFC5952 = false),
    "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"    -> ResultContainer(6, BigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16), strictRFC5952 = false),
    "FFFF:FFFF:FFFF:FFFG:FFFF:FFFF:FFFF:FFFF"    -> IPInvalidAddressComponents(remark = "No match at all: 'FFFF:FFFF:FFFF:FFFG…'."),
    "G::1"                                       -> IPInvalidAddressComponents(6, remark = "Invalid input 'G::1'."),
    "64:FF9B::192.0.2.33"                        -> ResultContainer(6, BigInt("0064FF9B0000000000000000C0000221", 16), strictRFC5952 = false),
    "64:FF9B::256.0.2.33" -> IPInvalidAddressComponents(6, BigInt("0064FF9B000000000000000000000000", 16), remark = "Invalid octets.")
    )

  def IPInvalidAddressComponents(version: Int = 0,
                                 address: BigInt = BigInt(0),
                                 port: Option[Int] = None,
                                 valid: Boolean = false,
                                 remark: String = "",
                                 strict: Boolean = false) = ResultContainer(version, address, port, valid, remark, strict)

  case class ResultContainer(version: Int,
                             address: BigInt,
                             port: Option[Int] = None,
                             valid: Boolean = true,
                             remark: String = "",
                             strictRFC5952: Boolean = true)

  class IpAddress(val originalString: String) {

    import IpAddress._

    val (usedPattern, result: ResultContainer) = originalString match {
      case trapPattern() => (trapPattern, IPInvalidAddressComponents(remark = s"Noise found: '${shortener(originalString)}'."))
      case allIpV6PortedPatternsCompiled(adr, port) => parseIpV6(adr, Option(port).map(_.toInt))
      case allIpV6UnspecPortPatternsCompiled(adr) => parseIpV6(adr)
      case ipV4PortSpecCompiled(adr, port) => (ipV4PortSpecCompiled, parseIpV4(adr, Option(port).map(_.toInt)))
      case _ => ("Exhausted of all matches.", IPInvalidAddressComponents(remark = s"No match at all: '${shortener(originalString, 19)}'."))
    }

    override def toString: String = {
      def hexAddr = if (result.version == 6) f"${result.address}%#034x" else f"${result.address}%#010x"

      def validInd = if (result.valid) '\u2714' else '\u2718'

      def rfc5952 = if (result.strictRFC5952) "comply" else "broken"

      def version = result.version match {
        case 0 => "   ?"
        case 4 => "IPv4"
        case 6 => "IPv6"
      }

      def surround(s: String) = if (result.valid) s" $s " else s"($s)"

      def port = if (result.port.isDefined) surround(result.port.get.toString) else if (result.valid) " " else "? "

      def hexAddrField = f"${if (result.valid || result.address != 0) surround(hexAddr) else "? "}%36s "

      f"${shortener(originalString, 45)}%46s $version $validInd $rfc5952 $hexAddrField $port%8s ${result.remark}%-40s $usedPattern"
    }

    def shortener(s: String, maxlength: Int = 12): String = {
      val size = s.length()
      s.substring(0, math.min(size, maxlength)) + (if (size > maxlength) "…" else "")
    }

    private def parseIpV6(ipAddress: String, port: Option[Int] = None): (String, ResultContainer) = {

      def colonedStringToBigInt(colonedString: String): (BigInt, Int) = {
        // Compressed zeroes expansion
        val ar = if (colonedString contains "::") colonedString.split("::", 2) else Array("", colonedString)
        val (left, right) = (ar.head.split(':').filterNot(_.isEmpty), ar(1).split(':').filterNot(_.isEmpty))
        val sixteenBitExpansions = 8 - (right.length + left.length)

        ((left ++ Seq.fill(sixteenBitExpansions)("0") ++ right)
          .map(BigInt(_, 16).toLong).map(BigInt(_)).reduceLeft((acc, i) => (acc << 16) | i),
          sixteenBitExpansions)
      }

      def parseEmbeddedV4(seg: String, ip4Seg: String, usedRegEx: String): (String, ResultContainer) = {
        val (ip4, ip6Parser, test) =
          (parseIpV4(ip4Seg), colonedStringToBigInt(seg.replaceFirst(ipV4Regex("3"), "0:0")), portNumberTest(port))

        (usedRegEx, ResultContainer(originalString, 6, ip4.address + ip6Parser._1, port,
          ip4.valid && test.isEmpty, ip4.remark + test, ip4.valid && test.isEmpty))
      }

      if (!ipAddress.forall((('A' to 'F') ++ ('a' to 'f') ++ ('0' to '9') ++ Vector(':', '.')).contains(_)))
        ("[^:.[0-9][A-F][a-f]]", IPInvalidAddressComponents(6, remark = s"Invalid input '${shortener(ipAddress)}'."))
      else
        ipAddress match {
          case pattern10Compiled(seg, ip4Seg) => parseEmbeddedV4(seg, ip4Seg, pattern10Compiled.toString())
          case pattern11Compiled(seg, ip4Seg) => parseEmbeddedV4(seg, ip4Seg, pattern11Compiled.toString())
          case ip6PatternsRawCompiled(seg, _*) =>
            val (ip6Parser, test) = (colonedStringToBigInt(seg), portNumberTest(port))

            (ip6PatternsRawCompiled.toString(),
              ResultContainer(ipAddress, 6, ip6Parser._1, port,
                valid = test.isEmpty, test, strictRFC5952 = ip6Parser._2 != 1 && test.isEmpty))
          case _ => ("V6 match exhausted.", IPInvalidAddressComponents(6, remark = "V6 address puntation error."))
        }
    } // parseIpV6


    private def parseIpV4(sIP: String, port: Option[Int] = None): ResultContainer = {

      def wordsToNum(words: Array[Long]): Long = words.reduceLeft((acc, i) => (acc << 8) | i)

      if (sIP.head.isDigit && sIP.matches(ipV4Regex("3"))) {
        val octets = sIP.split('.').map(_.toLong)
        if (octets.forall(_ < 256)) {
          val portNumberOK = portNumberTest(port)
          ResultContainer(4, BigInt(wordsToNum(octets)), port, portNumberOK.isEmpty, portNumberOK, portNumberOK.isEmpty)
        } else IPInvalidAddressComponents(4, remark = "Invalid octets.")
      }
      else IPInvalidAddressComponents(4, remark = s"Address puntation error: '${shortener(sIP)}'.")
    }

    private def portNumberTest(port: Option[Int]) = if (port.isEmpty || port.get < math.pow(2, 16)) "" else "Port number out of range."
  } // IpAddress

  object IpAddress {
    val (ip6PatternsRawCompiled, pattern11Compiled) = (ipV6Patterns.mkString("(", "|", ")").r, embeddedV4patterns()(1).r)
    val (trapPattern, pattern10Compiled) = (""".*?(?:(?:\w*:{2,}?){2,}?\w)|(?:\[?)""".r, embeddedV4patterns().head.r)
    val allIpV6PortedPatternsCompiled = ("""[^\\.]*?\[(""" + allIpV6 +""")\](?::(\d{1,6}))?[^\.:]*?""").r
    val allIpV6UnspecPortPatternsCompiled = (""".*?(""" + allIpV6 +""")[^\.:]*?""").r
    val ipV4PortSpecCompiled = s".*?([:.\\]]?${ipV4Regex()})(?::(\\d{1,6}))?.*?".r

    // Make a regex pattern with non-capturing groups by the disabling the capturing group syntax (?:).
    def allIpV6 = (embeddedV4patterns("(?:") ++ ipV6Patterns).map(s => "(?:" + s.drop(1)).mkString("|")

    def ipV6Patterns = {
      def ipV6SegRegWC = """\w{1,4}"""

      Seq(
        s"((?::(?:(?::$ipV6SegRegex){1,7}|:)))",
        s"((?:$ipV6SegRegWC:(?::$ipV6SegRegex){1,6}))",
        s"((?:$ipV6SegRegex:){1,2}(?::$ipV6SegRegex){1,5})",
        s"((?:$ipV6SegRegex:){1,3}(?::$ipV6SegRegex){1,4})",
        s"((?:$ipV6SegRegex:){1,4}(?::$ipV6SegRegex){1,3})",
        s"((?:$ipV6SegRegex:){1,5}(?::$ipV6SegRegex){1,2})",
        s"((?:$ipV6SegRegex:){1,6}:$ipV6SegRegex)",
        s"((?:$ipV6SegRegex:){1,7}:)",
        s"((?:$ipV6SegRegex:){7}$ipV6SegRegex)"
      )
    }

    private def embeddedV4patterns(nonCapturePrefix: String = "(") =
      Seq(s"(::(?:(?:FFFF|ffff)(?::0{1,4}){0,1}:){0,1}$nonCapturePrefix${ipV4Regex("3")}))",
        s"((?:$ipV6SegRegex:){1,4}:$nonCapturePrefix${ipV4Regex("3")}))")

    private def ipV6SegRegex = """[\dA-Fa-f]{1,4}"""

    private def ipV4Regex(octets: String = "3,") = s"(?:\\d{1,3}\\.){$octets}\\d{1,3}"
  }

  object ResultContainer {
    def apply(orginalString: String, version: Int,
              address: BigInt, port: Option[Int],
              valid: Boolean, remark: String,
              strictRFC5952: Boolean): ResultContainer =
    // To comply with strictRFC5952 all alpha character must be lowercase too.
      this (version, address, port, valid, remark, strictRFC5952 && !orginalString.exists(_.isUpper))
  }

  {
    val headline = Seq(f"${"IP addresses to be parsed. "}%46s", "Ver.", f"${"S"}%1s", "RFC5952",
      f"${"Hexadecimal IP address"}%34s", f"${"Port "}%10s", f"${" Remark"}%-40s", f"${" Effective RegEx"}%-40s")

    println(headline.mkString("|") + "\n" + headline.map(s => "-" * s.length).mkString("+"))

    val cases: Set[IpAddress] = myCases.keySet.map(new IpAddress(_))

    println(cases.toList.sortBy(s => (s.originalString.length, s.originalString)).mkString("\n"))
    logInfo(s"Concluding: ${myCases.size} cases processed, ${cases.count(_.result.valid)} valid ✔ and ${cases.count(!_.result.valid)} invalid ✘.")
    logInfo("Successfully completed without errors.")

    def logInfo(info: String) {
      println(f"[Info][${System.currentTimeMillis() - executionStart}%5d ms]" + info)
    }
  }

} // IPparser cloc.exe : 235 loc

Tcl

Library: Tcllib (Package: ip)
package require Tcl 8.5
package require ip

proc parseIP {address} {
    set result {}
    set family [ip::version $address]
    set port -1
    if {$family == -1} {
    if {[regexp {^\[(.*)\]:(\d+)$} $address -> address port]} {
        dict set result port $port
        set family [ip::version $address]
        if {$family != 6} {
        return -code error "bad address"
        }
    } elseif {[regexp {^(.*):(\d+)$} $address -> address port]} {
        dict set result port $port
        set family [ip::version $address]
        if {$family != 4} {
        return -code error "bad address"
        }
    } else {
        return -code error "bad address"
    }
    }
    # Only possible error in ports is to be too large an integer
    if {$port > 65535} {
    return -code error "bad port"
    }
    dict set result family $family
    if {$family == 4} {
    # IPv4 normalized form is dotted quad, but toInteger helps
    dict set result addr [format %x [ip::toInteger $address]]
    } else {
    # IPv6 normalized form is colin-separated hex
    dict set result addr [string map {: ""} [ip::normalize $address]]
    }
    # Return the descriptor dictionary
    return $result
}

Demonstration code:

foreach address {
    127.0.0.1
    127.0.0.1:80
    ::1
    [::1]:80
    2605:2700:0:3::4713:93e3
    [2605:2700:0:3::4713:93e3]:80
    ::ffff:192.168.0.1
    [::ffff:192.168.0.1]:22
    ::ffff:127.0.0.0.1
    a::b::1
    127.0.0.1:100000
} {
    if {[catch {
    set parsed [parseIP $address]
    } msg]} {
    puts "error ${msg}: \"$address\""
    continue
    }
    dict with parsed {
    puts -nonewline "family: IPv$family addr: $addr"
    if {[dict exists $parsed port]} {
        puts -nonewline " port: $port"
    }
    puts ""
    }
}

Output:

family: IPv4 addr: 7f000001
family: IPv4 addr: 7f000001 port: 80
family: IPv6 addr: 00000000000000000000000000000001
family: IPv6 addr: 00000000000000000000000000000001 port: 80
family: IPv6 addr: 260527000000000300000000471393e3
family: IPv6 addr: 260527000000000300000000471393e3 port: 80
family: IPv6 addr: 00000000000000000000ffffc0a80001
family: IPv6 addr: 00000000000000000000ffffc0a80001 port: 22
error bad address: "::ffff:127.0.0.0.1"
error bad address: "a::b::1"
error bad port: "127.0.0.1:100000"

VBScript

Function parse_ip(addr)
    'ipv4 pattern
    Set ipv4_pattern = New RegExp
    ipv4_pattern.Global = True
    ipv4_pattern.Pattern = "(\d{1,3}\.){3}\d{1,3}"
    'ipv6 pattern
    Set ipv6_pattern = New RegExp
    ipv6_pattern.Global = True
    ipv6_pattern.Pattern = "([0-9a-fA-F]{0,4}:){2}[0-9a-fA-F]{0,4}"
    'test if address is ipv4
    If ipv4_pattern.Test(addr) Then
        port = Split(addr,":")
        octet = Split(port(0),".")
        ipv4_hex = ""
        For i = 0 To UBound(octet)
            If octet(i) <= 255 And octet(i) >= 0 Then
                ipv4_hex = ipv4_hex & Right("0" & Hex(octet(i)),2)
            Else
                ipv4_hex = "Erroneous Address"
                Exit For
            End If 
        Next
        parse_ip = "Test Case: " & addr & vbCrLf &_
                   "Address: " & ipv4_hex & vbCrLf
        If UBound(port) = 1 Then
            If port(1) <= 65535 And port(1) >= 0 Then
                parse_ip = parse_ip & "Port: " & port(1) & vbCrLf
            Else
                parse_ip = parse_ip & "Port: Invalid" & vbCrLf
            End If
        End If
    End If
    'test if address is ipv6
    If ipv6_pattern.Test(addr) Then
        parse_ip = "Test Case: " & addr & vbCrLf
        port_v6 = "Port: "
        ipv6_hex = ""
        'check and extract port information if any
        If InStr(1,addr,"[") Then
            'extract the port
            port_v6 = port_v6 & Mid(addr,InStrRev(addr,"]")+2,Len(addr)-Len(Mid(addr,1,InStrRev(addr,"]")+1)))
            'extract the address
            addr = Mid(addr,InStrRev(addr,"[")+1,InStrRev(addr,"]")-(InStrRev(addr,"[")+1))
        End If
        word = Split(addr,":")
        word_count = 0
        For i = 0 To UBound(word)
            If word(i) = "" Then
                If i < UBound(word) Then
                    If Int((7-(i+1))/2) = 1 Then
                        k = 1
                    ElseIf UBound(word) < 6 Then
                        k = Int((7-(i+1))/2)
                    ElseIf UBound(word) >= 6 Then
                        k = Int((7-(i+1))/2)-1
                    End If
                    For j = 0 To k
                        ipv6_hex = ipv6_hex & "0000"
                        word_count = word_count + 1
                    Next
                Else
                    For j = 0 To (7-word_count)
                        ipv6_hex = ipv6_hex & "0000"
                    Next
                End If
            Else
                ipv6_hex = ipv6_hex & Right("0000" & word(i),4)
                word_count = word_count + 1
            End If
        Next
        parse_ip = parse_ip & "Address: " & ipv6_hex &_
                vbCrLf & port_v6 & vbCrLf
    End If
    'test if the address in invalid
    If ipv4_pattern.Test(addr) = False And ipv6_pattern.Test(addr) = False Then
        parse_ip = "Test Case: " & addr & vbCrLf &_
                   "Address: Invalid Address" & vbCrLf
    End If
End Function

'Testing the function
ip_arr = Array("127.0.0.1","127.0.0.1:80","::1",_
    "[::1]:80","2605:2700:0:3::4713:93e3","[2605:2700:0:3::4713:93e3]:80","RosettaCode")

For n = 0 To UBound(ip_arr)
    WScript.StdOut.Write parse_ip(ip_arr(n)) & vbCrLf
Next
Output:
Test Case: 127.0.0.1
Address: 7F000001

Test Case: 127.0.0.1:80
Address: 7F000001
Port: 80

Test Case: ::1
Address: 00000000000000000000000000000001
Port: 

Test Case: [::1]:80
Address: 00000000000000000000000000000001
Port: 80

Test Case: 2605:2700:0:3::4713:93e3
Address: 260527000000000300000000471393e3
Port: 

Test Case: [2605:2700:0:3::4713:93e3]:80
Address: 260527000000000300000000471393e3
Port: 80

Test Case: RosettaCode
Address: Invalid Address

V (Vlang)

Translation of: AutoHotkey
const data =
('
127.0.0.1
127.0.0.1:80
::1
[::1]:80
2605:2700:0:3::4713:93e3
[2605:2700:0:3::4713:93e3]:80
')

fn main() {
    mut output :=''
    for val in data.split('\n') {
        if val !='' {
            xarr := parse_ip(val)
            output += 'input = ' + val + '\t>\t' + xarr[0] + if xarr[1] !='' {' port : ' + xarr[1]} else {''} + '\n'
        }
    }
    println(output)
}

fn parse_ip(address string) []string {
    return if address.contains('.') {ipv4(address)} else {ipv6(address)}
}

fn ipv4(address string) []string {
    mut num, mut port := '', ''
    for val in address.split('.') {
        xarr := val.split(':')
        num += xarr[0].int().hex2().replace('x','')
        if xarr.len > 1 {port = xarr[1]} else {port =''}
    }
    return [num, port]
}

fn ipv6(address string) []string {
    mut num, mut port := '', ''
    for idx, val in address.split(']') {
        if idx == 0 {
            for xal in val.trim_left('[:').split(':') {
                if xal =='' {num += '00000000'} else {num += '0000'.substr(0, 4 - xal.len) + xal}
            }
        }
        else {port = val.trim_left(':')}
    }
    return ['00000000000000000000000000000000'.substr(0, 32 - num.len) + num, port]
}
Output:
input = 127.0.0.1	>	07f000001
input = 127.0.0.1:80	>	07f000001 port : 80
input = ::1	>	00000000000000000000000000000001
input = [::1]:80	>	00000000000000000000000000000001 port : 80
input = 2605:2700:0:3::4713:93e3	>	260527000000000300000000471393e3
input = [2605:2700:0:3::4713:93e3]:80	>	260527000000000300000000471393e3 port : 80

Wren

Translation of: Kotlin
Library: Wren-dynamic
Library: wren-big
Library: Wren-str
Library: Wren-fmt
import "./dynamic" for Enum, Tuple
import "./big" for BigInt
import "./str" for Str
import "./fmt" for Conv, Fmt

var AddressSpace = Enum.create("AddressSpace", ["IPv4", "IPv6", "Invalid"])

// a port of -1 denotes 'not specified'
var IPAddressComponents = Tuple.create("IPAddressComponents", ["address", "addressSpace", "port"])

var INVALID = IPAddressComponents.new(BigInt.zero, AddressSpace.Invalid, 0)

var ipAddressParse = Fn.new { |ipAddress|
    var addressSpace = AddressSpace.IPv4
    var ipa = Str.lower(ipAddress)
    var port = -1
    var trans = false

    if (ipa.startsWith("::ffff:") && ipa.contains(".")) {
        addressSpace = AddressSpace.IPv6
        trans = true
        ipa = ipa[7..-1]
    } else if (ipa.startsWith("[::ffff:") && ipa.contains(".")) {
        addressSpace = AddressSpace.IPv6
        trans = true
        ipa = ipa[8..-1].replace("]", "")
    }
    var octets = ipa.split(".")[-1..0].toList
    var address = BigInt.zero
    if (octets.count == 4) {
        var split = octets[0].split(":")
        if (split.count == 2) {
            var temp = Num.fromString(split[1])
            if (!temp || temp < 0 || temp > 65535) return INVALID
            port = temp
            octets[0] = split[0]
        }
        for (i in 0..3) {
            var num = Num.fromString(octets[i])
            if (!num || num < 0 || num > 255) return INVALID
            var bigNum = BigInt.new(num)
            address = address | (bigNum << (i * 8))
        } 
        if (trans) address = address + BigInt.fromBaseString("ffff00000000", 16)
    } else if (octets.count == 1) {
        addressSpace = AddressSpace.IPv6
        if (ipa[0] == "[") {
            ipa = ipa[1..-1]
            var split = ipa.split("]:")
            if (split.count != 2) return INVALID
            var temp = Num.fromString(split[1])
            if (!temp || temp < 0 || temp > 65535) return INVALID
            port = temp
            ipa = ipa[0...(-2 - split[1].count)]
        }
        var hextets = ipa.split(":")[-1..0].toList
        var len = hextets.count

        if (ipa.startsWith("::")) {
            hextets[-1] = "0"
        } else if (ipa.endsWith("::")) {
            hextets[0] = "0"
        }
        if (ipa == "::") hextets[1] = "0"
        if (len > 8 || (len == 8 && hextets.any { |h| h == "" }) || hextets.count { |h| h == "" } > 1) {
            return INVALID
        }
        if (len < 8) {
            var insertions = 8 - len
            for (i in 0..7) {
                if (hextets[i] == "") {
                    hextets[i] = "0"
                    while (insertions > 0) {
                        insertions = insertions - 1
                        hextets.insert(i, "0")
                    }
                    break
                }
            }
        }
        for (j in 0..7) {
            var num = Conv.atoi(hextets[j], 16)
            if (num > 0xFFFF) return INVALID
            var bigNum = BigInt.new(num)
            address = address | (bigNum << (j * 16))
        }
    } else return INVALID

    return IPAddressComponents.new(address, addressSpace, port)
}

var ipas = [
    "127.0.0.1",
    "127.0.0.1:80",
    "::1",
    "[::1]:80",
    "2605:2700:0:3::4713:93e3",
    "[2605:2700:0:3::4713:93e3]:80",
    "::ffff:192.168.173.22",
    "[::ffff:192.168.173.22]:80",
    "1::",
    "::",
    "256.0.0.0",
    "::ffff:127.0.0.0.1"
]
for (ipa in ipas) {
    var ipac = ipAddressParse.call(ipa)
    Fmt.print("IP address    : $s", ipa)
    Fmt.print("Address       : $s", Str.upper(ipac.address.toBaseString(16)))
    Fmt.print("Address Space : $s", AddressSpace.members[ipac.addressSpace])
    Fmt.print("Port          : $s", (ipac.port == -1) ? "not specified" : ipac.port.toString)
    System.print()
}
Output:
IP address    : 127.0.0.1
Address       : 7F000001
Address Space : IPv4
Port          : not specified

IP address    : 127.0.0.1:80
Address       : 7F000001
Address Space : IPv4
Port          : 80

IP address    : ::1
Address       : 1
Address Space : IPv6
Port          : not specified

IP address    : [::1]:80
Address       : 1
Address Space : IPv6
Port          : 80

IP address    : 2605:2700:0:3::4713:93e3
Address       : 260527000000000300000000471393E3
Address Space : IPv6
Port          : not specified

IP address    : [2605:2700:0:3::4713:93e3]:80
Address       : 260527000000000300000000471393E3
Address Space : IPv6
Port          : 80

IP address    : ::ffff:192.168.173.22
Address       : FFFFC0A8AD16
Address Space : IPv6
Port          : not specified

IP address    : [::ffff:192.168.173.22]:80
Address       : FFFFC0A8AD16
Address Space : IPv6
Port          : 80

IP address    : 1::
Address       : 10000000000000000000000000000
Address Space : IPv6
Port          : not specified

IP address    : ::
Address       : 0
Address Space : IPv6
Port          : not specified

IP address    : 256.0.0.0
Address       : 0
Address Space : Invalid
Port          : 0

IP address    : ::ffff:127.0.0.0.1
Address       : 0
Address Space : Invalid
Port          : 0