1

I have a strings as mentioned in the below format, i would like to remove only IPv6 address from the string and print only the IPv4 address as a string. I tried with sub string and regex , but I am unable to get correct regex for this string. Could any one help to provide the solution.

Actual format of Inputs string given to python program as below format (square brackets included), Where Ipv6 address can be present either at starting or ending of the string.

['fe80::2ff:fe21:30f/64', '17.2.1.2/24']
['fe80::2ff:fee4:2b43/64', '17.2.1.3/24']
['17.2.10.2/24', 'fe80::2ff:fe42:f251/64]
['192.168.4.1/30', 'fe80::2ff:fe19:cdd7/64']
['fe80::2ff:fe1e:e328/64', '17.2.4.1/24']

Output should be display as only ipv4 address as strings

   "17.2.1.2/24"
   "17.2.1.3/24"
   "17.2.10.2/24"
   "192.168.4.1/30"
   "17.2.4.1/24"
Brad Solomon
  • 29,156
  • 20
  • 104
  • 175
rishi narian
  • 343
  • 1
  • 11
  • 2
    I don't think there's a need to mess around with regex. just try checking the string with `if ":" not in str` – Tim Lee Feb 26 '18 at 04:24
  • XY problem. Why are the strings printed as such? you could use `ast.literal_eval(line)[1]` that would work, but the best way would be to change the input file format – Jean-François Fabre Feb 26 '18 at 04:24
  • Shouldn't be too hard to figure out. IPv6 addresses have :'s in them, IPv4 don't. – Red Cricket Feb 26 '18 at 04:24

3 Answers3

4

Firstly, it's a technical detail, but just be aware that in your lists, none of the addresses are technically valid IPv4, because of the trailing slashes (which, I'm assuming, indicates a range). In the docs for Python's ipaddress module, you can find the description for what constitutes a valid address.

That said, reading between the lines a bit, if you want to be thorough here (rather than just checking for ":" as suggested in the comments, remove the ranges, then try to instantiate an ipaddress.IPv4Address class instance. If this fails, you don't have a valid address.

from ipaddress import IPv4Address, AddressValueError

addresses = ['fe80::2ff:fe21:30f/64', '17.2.1.2/24',
             'fe80::2ff:fee4:2b43/64', '17.2.1.3/24',
             '17.2.10.2/24', 'fe80::2ff:fe42:f251/64',
             '192.168.4.1/30', 'fe80::2ff:fe19:cdd7/64',
             'fe80::2ff:fe1e:e328/64', '17.2.4.1/24']

def is_ipv4_only(addr):
    try:
        IPv4Address(addr.split('/')[0])
        return True
    except AddressValueError:
        return False

for address in addresses:
    if is_ipv4_only(address):
        print(address)

17.2.1.2/24
17.2.1.3/24
17.2.10.2/24
192.168.4.1/30
17.2.4.1/24

Alternatively (and this is overkill) you could use a regex for IPv4s. (The IPv6 regex is way hairier than this; I've seen people take a stab at it but I'm not one of them.)

ipv4 = re.compile(r'\b(([0]{1,2}[0-7]|[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0]{1,2}[0-7]|[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b')
Brad Solomon
  • 29,156
  • 20
  • 104
  • 175
1

you have several issues:

  • parse the python formatted lists: use ast.literal_eval for each line
  • filter out the proper addresses. A good criterion is to check that colon is not in the string.

My approach is one-line, using next and a generator to return the only (or empty string) valid string in each line:

text="""['fe80::2ff:fe21:30f/64', '17.2.1.2/24']
['fe80::2ff:fee4:2b43/64', '17.2.1.3/24']
['17.2.10.2/24', 'fe80::2ff:fe42:f251/64']
['192.168.4.1/30', 'fe80::2ff:fe19:cdd7/64']
['fe80::2ff:fe1e:e328/64', '17.2.4.1/24']""".splitlines()

import ast

result = [next((x for x in ast.literal_eval(line) if ":" not in x),"") for line in text]

print(result)

prints:

['17.2.1.2/24', '17.2.1.3/24', '17.2.10.2/24', '192.168.4.1/30', '17.2.4.1/24']

(result is a python list, so printing the lines without the brackets and all just requires a loop or str.join)

Jean-François Fabre
  • 126,787
  • 22
  • 103
  • 165
0

You can easy detect all values with double :: and remove them.

mlist = ['fe80::2ff:fe21:30f/64', '17.2.1.2/24', 'fe80::2ff:fee4:2b43/64', '17.2.1.3/24']
ipv4 = []
for cidr in mlist:
    if not "::" in cidr:
        ipv4.append(cidr)
print(ipv4)

Output : ['17.2.1.2/24', '17.2.1.3/24']

Anass
  • 1,458
  • 2
  • 11
  • 18