Various comments in no specific order.
The 2 last statements are identical, thus it is not relevant to check invalid_segment
.
You could write:
if len(address) == len(is_valid) and len(address_list) == 8 and invalid_segment == False:
print("It is a valid IPv6 address.")
else:
print("It is not a valid IPv6 address.")
It would be clearer to write a function returning a boolean to check the address. It makes your code easier to understand and easier to re-use. Also, you could move the part handling the input/output behind an if __name__ == "__main__":
guard.
You'd get:
valid_characters = ['A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f', ':', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
def ipv6_addr_is_valid(address):
is_valid = []
for i in range(len(address)):
current = address[i]
for j in range(len(valid_characters)):
check = valid_characters[j]
if check == current:
a = 1
is_valid.append(a)
address_list = address.split(":")
invalid_segment = False
for i in range(len(address_list)):
current = address_list[i]
if len(current) > 4:
invalid_segment = True
return len(address) == len(is_valid) and len(address_list) == 8 and invalid_segment == False
if __name__ == "__main__":
address = input('Please enter an IP address: ')
if ipv6_addr_is_valid(address):
print("It is a valid IPv6 address.")
else:
print("It is not a valid IPv6 address.")
Usually, when you use indices, range
and len
to iterate over an array in Python, you're doing it wrong. I highly recommend watching the talk "Loop Like A Native" from Ned Batchelder, it will help to write more concise, faster, easier to reuse code. In a nutshell, the for
loop acts as a foreach
loop so most of the time, you don't need to handle indices at all.
You'd get something like:
def ipv6_addr_is_valid(address):
is_valid = []
for current in address:
for valid in valid_characters:
if valid == current:
a = 1
is_valid.append(a)
address_list = address.split(":")
invalid_segment = False
for current in address_list:
if len(current) > 4:
invalid_segment = True
return len(address) == len(is_valid) and len(address_list) == 8 and invalid_segment == False
You use a is_valid
list and use its number of elements to know whether the address is valid. Things could be done in a more efficient way. Let's do it in many small steps for education purposes.
you could count values instead of adding them to a list
nb_valid = 0
for current in address:
for valid in valid_characters:
if valid == current:
nb_valid += 1
...
return len(address) == nb_valid and len(address_list) == 8 and invalid_segment == False
you could break out of the valid_characters
loops as soon as you've found a match.
in Python, for
loops accept a else
part meaning "this loop exited the normal way: it didn't encounter a break
". You could use this to return False
as soon as a character is invalid.
for current in address:
for valid in valid_characters:
if valid == current:
nb_valid += 1
break
else: # nobreak - invalid character
return False
Thus, you don't even need to count nb_valid
anymore:
for current in address:
for valid in valid_characters:
if valid == current:
break
else: # nobreak - invalid character
return False
You could use in
to check if character is valid:
for current in address:
if current not in valid_characters:
return False
You could initialise valid_characters
in a more concise way in a single string:
valid_characters = 'ABCDEFabcdef:0123456789'
then you could make the in
lookup for efficient by using a set
:
valid_characters = set('ABCDEFabcdef:0123456789')
You could break
after finding an invalid segment. You could also return False directly and get rid of the variable:
for current in address_list:
if len(current) > 4:
return False # Invalid segment
At this stage, the code looks like:
valid_characters = set('ABCDEFabcdef:0123456789')
def ipv6_addr_is_valid(address):
for current in address:
if current not in valid_characters:
return False
address_list = address.split(":")
for current in address_list:
if len(current) > 4:
return False # Invalid segment
return len(address_list) == 8
if __name__ == "__main__":
print(ipv6_addr_is_valid("0:0:0:0:0:0:0:1"))
# address = input('Please enter an IP address: ')
# if ipv6_addr_is_valid(address):
# print("It is a valid IPv6 address.")
# else:
# print("It is not a valid IPv6 address.")
You could use all
/any
to make some parts of your code more concise. It doesn't help too much in your case because you are using return
already.
def ipv6_addr_is_valid(address):
if any(c not in valid_characters for c in address):
return False
address_list = address.split(":")
if any(len(c) > 4 for c in address_list):
return False # Invalid segment
return len(address_list) == 8
Which can be re-organised:
def ipv6_addr_is_valid(address):
address_list = address.split(":")
return len(address_list) == 8 and all(c in valid_characters for c in address) and all(len(c) <= 4 for c in address_list)
::1
and to accept1::3:::6::8
\$\endgroup\$