I'm writing an application in which i receive from a socket a string like '2227275982'. How would I convert this into dotted quad IP address form? Every time I try to use the number I get OverflowError: integer literal too large. Anyone got any ideas?
>I'm writing an application in which i receive from a socket a string like >'2227275982'. How would I convert this into dotted quad IP address form? >Every time I try to use the number I get OverflowError: integer literal >too large. Anyone got any ideas?
sbarron@twilight. (Scott Barron) writes: > I'm writing an application in which i receive from a socket a string like > '2227275982'. How would I convert this into dotted quad IP address form? > Every time I try to use the number I get OverflowError: integer literal > too large. Anyone got any ideas?
Hm... tricky. Time for one of c.l.p's patented analysis threads: Is it even possible to go from a string of numbers to the dotted quad form? The example string doesn't produce a legal result, for example, probably because an extra digit crept in. Starting at the left and taking as many digits as we can, you get: 222 72 75 982. From the right, you wind up with: 2227 27 59 82.
If you allow arbitrary numbers of leading zeros, I think it's not possible to do this unambiguously; is 255000200 255.0.2.0 or 255.0.0.200? If we assume that only a single leading zero is allowed to indicate an octal number, it's still ambiguous: '102710140' can be either 102.71.014.0 or 102.71.0.140. If we disallow octal and leading zeros completely, the same string can be '10.27.10.140' or '10.27.101.40' or '102.7.10.140', etc. Unless I've missed something, this problem is unsolvable, so start putting the dots back into your protocol...
Appended is some evil regex hackery I wrote while attempting to solve this.
-- A.M. Kuchling http://starship.python.net/crew/amk/ I lack the ability to embellish. Thus you would perforce needs content all yourselves, one and all, with a rather sparse and uninteresting narrative. -- Cluracan warms up, in SANDMAN #52: "Cluracan's Tale"
import re
number_pat = re.compile(r""" # Octal versions 0(?: [123][0-7][0-7] | # Octal 100-377 [1-7][0-7] | # Two digit octal numbers [1-7] # One digit octal numbers ) | 1\d\d | # Decimal 1xx 2[0-4]\d | # Match decimal numbers from 200 to 249 25[0-5] | # Match decimal numbers from 250 to 255 [1-9]\d | # 2-digit decimal numbers [0-9] # One-digit decimal numbers """, re.VERBOSE)
# This pattern matches 4 repetitions of the number pattern, and uses # ^,$ to require matching the entire string. quad_pat = re.compile("^" + '('+number_pat.pattern+'){4}$', re.VERBOSE)
# Now we build a list of 4 patterns, all slight variations on the same plan: # ^( <number pattern> )(?: <number pattern> )(?: <number pattern> )(?: <number pattern> )$ # ^(?: <number pattern> )( <number pattern> )(?: <number pattern> )(?: <number pattern> )$ # ^(?: <number pattern> )(?: <number pattern> )( <number pattern> )(?: <number pattern> )$ # ^(?: <number pattern> )(?: <number pattern> )(?: <number pattern> )( <number pattern> )$ # Using all four of them, you can read off the 4 consecutive quads in group 1 of each pattern.
patlist = [] for i in range(4): patlist.append( re.compile("^" + i*('(?:'+number_pat.pattern+')') + '('+number_pat.pattern+')' + (3-i)*('(?:'+number_pat.pattern+')') + "$", re.VERBOSE) )
for ip in ['222727598', '255255002', '0000', '102710140', '020000']: m = quad_pat.match(ip) if m is None: print ip, "can't be valid IP address" ; continue
# Print 4 consective quads print ip, '->', for p in patlist: print p.match( ip ).group(1), '.', print
The string is a representation of the IP address as a long int in network byte order. For example 16777343 would be 127.0.0.1. So it can't be translated direcly. What I ended up doing was something like this: hex (string.atol ('16777343')) which would give me something like 0x100007FL. Then I started from the end and each byte (ie 7F) is a number in the IP address. I started from the end because hex() did not add the extra 0 before the one so you'd really not know if the first byte was supposed to be 01 or 10. Then I just added the results together with the dots. I think this should work on all systems since the string representation is always in network byte order. Here is the function I came up with:
>sbarron@twilight. (Scott Barron) writes: >> I'm writing an application in which i receive from a socket a string like >> '2227275982'. How would I convert this into dotted quad IP address form? >> Every time I try to use the number I get OverflowError: integer literal >> too large. Anyone got any ideas?
>Hm... tricky. Time for one of c.l.p's patented analysis threads: Is >it even possible to go from a string of numbers to the dotted quad >form? The example string doesn't produce a legal result, for example, >probably because an extra digit crept in. Starting at the left and >taking as many digits as we can, you get: 222 72 75 982. >From the right, you wind up with: 2227 27 59 82.
>If you allow arbitrary numbers of leading zeros, I think it's not >possible to do this unambiguously; is 255000200 255.0.2.0 or >255.0.0.200? If we assume that only a single leading zero is allowed >to indicate an octal number, it's still ambiguous: '102710140' can be >either 102.71.014.0 or 102.71.0.140. If we disallow octal and leading >zeros completely, the same string can be '10.27.10.140' or >'10.27.101.40' or '102.7.10.140', etc. Unless I've missed something, >this problem is unsolvable, so start putting the dots back into your >protocol...
sbarron@twilight. (Scott Barron) writes: > The string is a representation of the IP address as a long int in network > byte order. For example 16777343 would be 127.0.0.1. So it can't be > translated direcly. What I ended up doing was something like this:
Oops, there I go solving the wrong problem again.
Have you looked at the struct module? Here's an alternative solution:
def transip2 (ipstr): # Pack into a 4-byte integer s = struct.pack('!L', string.atol(ipstr) )
# Unpack as 4 bytes L = struct.unpack('!4B', s)
return `L[3]`+'.' + `L[2]`+'.'+`L[1]`+'.'+`L[0]`
Also, transip() will crash if the number is so small that it produces less than 8 digits (unlikely, for real network addresses). There should be 'hv=string.zfill(hv, 8)' added to it.
-- A.M. Kuchling http://starship.python.net/crew/amk/ When I dream, sometimes I remember how to fly. You just lift one leg, then you lift the other leg, and you're not standing on anything, and you can fly. -- Chloe Russell, in SANDMAN #43: "Brief Lives:3"
You may need to play games if the network order doesn't match your processors byte order but thats just as easy. So is figuring out which to use automatically.
>sbarron@twilight. (Scott Barron) writes: >> The string is a representation of the IP address as a long int in network >> byte order. For example 16777343 would be 127.0.0.1. So it can't be >def transip2 (ipstr): > # Pack into a 4-byte integer > s = struct.pack('!L', string.atol(ipstr) )
> # Unpack as 4 bytes > L = struct.unpack('!4B', s)