Using a RegEx to match IP addresses - python

I'm trying to make a test for checking whether a sys.argv input matches the RegEx for an IP address...
As a simple test, I have the following...
import re
pat = re.compile("\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}")
test = pat.match(hostIP)
if test:
print "Acceptable ip address"
else:
print "Unacceptable ip address"
However when I pass random values into it, it returns "Acceptable IP address" in most cases, except when I have an "address" that is basically equivalent to \d+.

Using regex to validate IP address is a bad idea - this will pass 999.999.999.999 as valid. Try this approach using socket instead - much better validation and just as easy, if not easier to do.
import socket
def valid_ip(address):
try:
socket.inet_aton(address)
return True
except:
return False
print valid_ip('10.10.20.30')
print valid_ip('999.10.20.30')
print valid_ip('gibberish')
If you really want to use parse-the-host approach instead, this code will do it exactly:
def valid_ip(address):
try:
host_bytes = address.split('.')
valid = [int(b) for b in host_bytes]
valid = [b for b in valid if b >= 0 and b<=255]
return len(host_bytes) == 4 and len(valid) == 4
except:
return False

You have to modify your regex in the following way
pat = re.compile("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
that's because . is a wildcard that stands for "every character"

regex for ip v4:
^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
otherwise you take not valid ip address like 999.999.999.999, 256.0.0.0 etc

I came across the same situation, I found the answer with use of socket library helpful but it doesn't provide support for ipv6 addresses. Found a better way for it:
Unfortunately, it Works for python3 only
import ipaddress
def valid_ip(address):
try:
print (ipaddress.ip_address(address))
return True
except:
return False
print (valid_ip('10.10.20.30'))
print (valid_ip('2001:DB8::1'))
print (valid_ip('gibberish'))

You are trying to use . as a . not as the wildcard for any character. Use \. instead to indicate a period.

def ipcheck():
# 1.Validate the ip adderess
input_ip = input('Enter the ip:')
flag = 0
pattern = "^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$"
match = re.match(pattern, input_ip)
if (match):
field = input_ip.split(".")
for i in range(0, len(field)):
if (int(field[i]) < 256):
flag += 1
else:
flag = 0
if (flag == 4):
print("valid ip")
else:
print('No match for ip or not a valid ip')

import re
ipv=raw_input("Enter an ip address")
a=ipv.split('.')
s=str(bin(int(a[0]))+bin(int(a[1]))+bin(int(a[2]))+bin(int(a[3])))
s=s.replace("0b",".")
m=re.search('\.[0,1]{1,8}\.[0,1]{1,8}\.[0,1]{1,8}\.[0,1]{1,8}$',s)
if m is not None:
print "Valid sequence of input"
else :
print "Invalid input sequence"
Just to keep it simple I have used this approach.
Simple as in to explain how really ipv4 address is evaluated.
Checking whether its a binary number is although not required.
Hope you like this.

str = "255.255.255.255"
print(str.split('.'))
list1 = str.split('.')
condition=0
if len(list1)==4:
for i in list1:
if int(i)>=0 and int(i)<=255:
condition=condition+1
if condition!=4:
print("Given number is not IP address")
else:
print("Given number is valid IP address")

If you really want to use RegExs, the following code may filter the non-valid ip addresses in a file, no matter the organiqation of the file, one or more per line, even if there are more text (concept itself of RegExs) :
def getIps(filename):
ips = []
with open(filename) as file:
for line in file:
ipFound = re.compile("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$").findall(line)
hasIncorrectBytes = False
try:
for ipAddr in ipFound:
for byte in ipAddr:
if int(byte) not in range(1, 255):
hasIncorrectBytes = True
break
else:
pass
if not hasIncorrectBytes:
ips.append(ipAddr)
except:
hasIncorrectBytes = True
return ips

re.sub('((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])', '--', '127.0.0.1')
With this regular expression, only numbers from 0 to 255 could compose the address. It also handles leading zeros, so 127.00.0.1 would no pass.

IP address uses following authentication :
255 ---> 250-255
249 ---> 200-249
199 ---> 100-199
99 ---> 10-99
9 ---> 1-9
import re
k = 0
while k < 5 :
i = input("\nEnter Ip address : ")
ip = re.match("^([1][0-9][0-9].|^[2][5][0-5].|^[2][0-4][0-9].|^[1][0-9][0-9].|^[0-9][0-9].|^[0-9].)([1][0-9][0-9].|[2][5][0-5].|[2][0-4][0-9].|[1][0-9][0-9].|[0-9][0-9].|[0-9].)([1][0-9][0-9].|[2][5][0-5].|[2][0-4][0-9].|[1][0-9][0-9].|[0-9][0-9].|[0-9].)([1][0-9][0-9]|[2][5][0-5]|[2][0-4][0-9]|[1][0-9][0-9]|[0-9][0-9]|[0-9])$",i)
k = k + 1
if ip:
print ("\n=====================")
print ("Valid IP address")
print ("=====================")
break
else :
print ("\nInvalid IP")
else :
print ("\nAllowed Max 5 times")
Reply me if you have doubt?

import re
st1 = 'This is my IP Address10.123.56.25 789.356.441.561 127 255 123.55 192.168.1.2.3 192.168.2.2 str1'
Here my valid IP Address is only 192.168.2.2 and assuming 10.123.56.25 is not a valid one as it is combined with some string and 192.168.1.2.3 not valid.
pat = r'\s(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\s|$))'
match = re.search(pat,st1)
print match.group()
================ RESTART: C:/Python27/Srujan/re_practice.py ================
192.168.2.2
This will grep the exact IP Address, we can ignore any pattern look like an IP Address but not a valid one. Ex: 'Address10.123.56.25', '789.356.441.561' '192.168.1.2.3'.
Please comment if any modifications are required.

This works for python 2.7:
import re
a=raw_input("Enter a valid IP_Address:")
b=("[0-9]+"+".")+"{3}"
if re.match(b,a) and b<255:
print "Valid"
else:
print "invalid"

""" regex for finding valid ip address """
import re
IPV4 = re.fullmatch('([0-2][0-5]{2}|\d{2}|\d).([0-2][0-5]{2}|\d{2}|\d).([0-2][0-5]{2}|\d{2}|\d).([0-2][0-5]{2}|\d{2}|\d)', '100.1.1.2')
if IPV4:
print ("Valid IP address")
else:
print("Invalid IP address")

Related

How to filter characters for comparison of strings in Python

i am very new to coding and I am not familiar with python, could you guys give me maybe a small example of how you would solve this problem.
Basically this new device i will be working on has a 2D code(its sort of a barcode kkind of thing) and when i scan the code witha 2D scanner a string like this shows up on my notepad for example: 58183#99AF0M000F9EF3F800
the last 12 characters are the MAC address and the first 5 characters are the order number.
i need to compare that(58183#99AF0M000F9EF3F800) with the MAC address value i get from the XML page.
here is the terminal output for more reference:
####################################################################################################
Current device information:
Order-number: 58184 Software-version: 1.0.0 ( Build : 1 ) Hardware version: 1.00 MAC address: 00:0F:9E:F4:1A:80
desired-Order-number: 58183 desired-Softwareversion: 1.0.0 ( Build : 1 ) desired-hardwareversion: 1.00 pc-praefix: 7A2F7
PASS
PS C:\Users\Aswin\Python Project>
The MAC address from the XML page has looks like this "00:0F:9E:F4:1A:80" and the 2D scancode looks like this "58183#99AF0M000F9EF3F800". how can i take the last 12 characters of this scan code and compare it with the mac address from the XML page to see if they match.
Any example of code blocks would be much appreciated guys.
try:
preflash = urllib.request.urlopen("http://10.10.10.2", timeout=3).getcode()
print("Web page status code:", preflash, "FAIL")
sys.exit(0)
except urllib.error.URLError:
correct = urllib.request.urlopen("http://192.168.100.5", timeout=10).getcode()
print("Web page status code:", correct)
print("IP address: 192.168.100.5 is reachable")
print(100*"#")
# Declare url String
url_str = 'http://192.168.100.2/globals.xml'
# open webpage and read values
xml_str = urllib.request.urlopen(url_str).read()
# Parses XML doc to String for Terminal output
xmldoc = minidom.parseString(xml_str)
# prints the order_number from the xmldoc
order_number = xmldoc.getElementsByTagName('order_number')
ord_nmr = order_number[0].firstChild.nodeValue
# prints the firmware_version from the xmldoc
firmware_version = xmldoc.getElementsByTagName('firmware_version')
frm_ver = firmware_version[0].firstChild.nodeValue
# prints the hardware_version from the xmldoc
hardware_version = xmldoc.getElementsByTagName('hardware_version')
hrd_ver = hardware_version[0].firstChild.nodeValue
v = hrd_ver.split()[-1]
# prints the mac_address from the xmldoc
mac_address = xmldoc.getElementsByTagName('mac_address')
mac_addr = mac_address[0].firstChild.nodeValue
print("Current device information: ")
print("Order-number: ",ord_nmr, "Software-version: ",frm_ver, "Hardware version: ",v, "MAC address: ",mac_addr)
d_ordernum = "58183"
d_hw_version = "1.00"
d_sf_version = "1.0.0 ( Build : 1 )"
pc_praefix = "7A2F7"
print("desired-Order-number: 58183 desired-Softwareversion: 1.0.0 ( Build : 1 ) desired-hardwareversion: 1.00 pc-praefix: 7A2F7")
if d_sf_version == frm_ver:
print("PASS")
else:
print("FAIL")
You could take the string from the scan code and slice it
scan_code_cropped = scancode_string[11:]
This will get you the last 12 characters of the scan code.
Now to get the MAC address in a format to be able to compare it to the scan code, split it on the basis of ":"
list_of_chars = mac_address_string.split(":")
this will get you the character list, which can be concatenated using
mac_address_string_joined = ''.join(list_of_chars)
and finally to compare the two strings
if scan_code_cropped == mac_address_string_joined:
print("Mac address & Scan code matched !")
If needed in a function format, here you go:
def match_scan_with_mac(scancode_string, mac_address_string):
# get the last 12 characters of the scan code
scan_code_cropped = scancode_string[11:]
# get the mac address without the ":"
list_of_chars = mac_address_string.split(":")
mac_address_string_joined = ''.join(list_of_chars)
# compare the MAC address and the scan string
if scan_code_cropped == mac_address_string_joined:
print("Mac address & Scan code matched !")
return True
return False

Increment an IP address when the IP address is given in steps in python

How do I increment the IP address in python when we have start_ip in 4 octets format and the step also in 4 octet format.
Let's suppose I start with an IP address of 225.1.1.1, and the step as 0.0.0.1
When I say next_ip = start_ip + step, it should actually evaluate the expand produce the result.
I know that the ipaddr module does this with just an addition, but that does not seem to work when the step is also given in the ipv4 format.
Any known steps to do this:
import ipaddr
a = ipaddr.ipaddress('225.1.1.1')
b = a +1
This actually returns the desired result. but when increment like this:
b = a + 0.0.0.1 it does not seem to work.
Any known solutions for this?
Not refined but works i guess, here is the python snippet
def increment_ip_addr(ip_addr):
ip_arr = ip_addr.split('.')
def increment_by_1(digit):
return str(int(digit) + 1)
if int(ip_arr[3]) > 254:
ip_arr[3] = "1"
if int(ip_arr[2]) > 254:
ip_arr[2] = "1"
if int(ip_arr[1]) > 254:
ip_arr[1] = "1"
if int(ip_arr[0]) > 254:
ip_arr[0] = "1"
else:
ip_arr[0] = increment_by_1(ip_arr[0])
else:
ip_arr[1] = increment_by_1(ip_arr[1])
else:
ip_arr[2] = increment_by_1(ip_arr[2])
else:
ip_arr[3] = increment_by_1(ip_arr[3])
print(f"for ip address: {ip_addr} The incremented ip is: {'.'.join(ip_arr)}")
[increment_ip_addr(ip_addr) for ip_addr in ['1.1.1.1', "1.1.1.255", "1.255.1.255", "255.255.255.255"]]
corresponding console output:
for ip address: 1.1.1.1 The incremented ip is: 1.1.1.2
for ip address: 1.1.1.255 The incremented ip is: 1.1.2.1
for ip address: 1.255.1.255 The incremented ip is: 1.255.2.1
for ip address: 255.255.255.255 The incremented ip is: 1.1.1.1
Let me know in case of optimized version
this piece of code can add two 4 octets :
first = '192.168.0.4'
second = '0.0.0.1'
ipaddress.ip_address(first) + int(ipaddress.ip_address(second))
this will result in: IPv4Address('192.168.0.5')

Find USB serial port with Python script

I am trying to write a script in python so I can find in 1 sec the COM number of the USB serial adapter I have plugged to my laptop.
What I need is to isolate the COMx port so I can display the result and open putty with that specific port. Can you help me with that?
Until now I have already written a script in batch/powershell and I am getting this information but I havent been able to separate the text of the COMx port so I can call the putty program with the serial parameter.
I have also been able to find the port via Python but I cant isolate it from the string.
import re # Used for regular expressions (unused)
import os # To check that the path of the files defined in the config file exist (unused)
import sys # To leave the script if (unused)
import numpy as np
from infi.devicemanager import DeviceManager
dm = DeviceManager()
dm.root.rescan()
devs = dm.all_devices
print ('Size of Devs: ',len(devs))
print ('Type of Devs: ',type(devs))
myarray = ([])
myarray =np.array(devs)
print ('Type of thing: ',type(myarray))
match = '<USB Serial Port (COM6)>' (custom match. the ideal would be "USB Serial Port")
i=0
#print (myarray, '\n')
while i != len(devs):
if match == myarray[i]:
print ('Found it!')
break
print ('array: ',i," : ", myarray[i])
i = i+1
print ('array 49: ', myarray[49]) (here I was checking what is the difference of the "element" inside the array)
print ('match : ', match) (and what is the difference of what I submitted)
print ('end')
I was expecting the if match == myarray[i] to find the two elements but for some reason it doesnt. Its returning me that those two are not the same.
Thank you for any help in advance!
=== UPDATE ===
Full script can be found here
https://github.com/elessargr/k9-serial
this is a follow up answer from #MacrosG
i tried a minimal example with properties from Device
from infi.devicemanager import DeviceManager
dm = DeviceManager()
dm.root.rescan()
devs = dm.all_devices
print ('Size of Devs: ',len(devs))
for d in devs:
if "USB" in d.description :
print(d.description)
If Python says the strings are not the same I dare say it's quite likely they are not.
You can compare with:
if "USB Serial Port" in devs[i]:
Then you should be able to find not a complete letter by letter match but one that contains a USB port.
There is no need to use numpy, devs is already a list and hence iterable.
If you want to do this with regular-expressions:
def main():
from infi.devicemanager import DeviceManager
import re
device_manager = DeviceManager()
device_manager.root.rescan()
pattern = r"USB Serial Port \(COM(\d)\)"
for device in device_manager.all_devices:
try:
match = re.fullmatch(pattern, device.friendly_name)
except KeyError:
continue
if match is None:
continue
com_number = match.group(1)
print(f"Found device \"{device.friendly_name}\" -> com_number: {com_number}")
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
Output:
Found device "USB Serial Port (COM3)" -> com_number: 3
Huge thanks to everyone and especially to bigdataolddriver since I went with his solution
Last thing!
for d in devs:
if "USB Serial Port" in d.description :
str = d.__str__()
COMport = str.split('(', 1)[1].split(')')[0]
i=1
break
else:
i=0
if i == 1:
print ("I found it!")
print(d.description, "found on : ", COMport)
subprocess.Popen(r'"C:\Tools\putty.exe" -serial ', COMport)
elif i ==0:
print ("USB Serial Not found \nPlease check physical connection.")
else:
print("Error")
Any ideas how to pass the COMport to the putty.exe as a parameter?
===== UPDATE =====
if i == 1:
print ("I found it!")
print(d.description, "found on : ", COMport)
command = '"C:\MyTools\putty.exe" -serial ' + COMport
#print (command)
subprocess.Popen(command)
Thank you everyone!

How do i search in a telnet session output with re a string where x is a number between 1 and 99999?

import getpass
import sys
import telnetlib
import re
import smtplib
print "Pasul 1"
HOST = "route-views.routeviews.org"
user = "rviews"
password = ""
tn = telnetlib.Telnet(HOST)
tn.read_until("login: ", 5)
tn.write(user + "\r\n")
tn.read_until("Password: ", 5)
tn.write(password + "\r\n")
print tn.read_until(">", 10)
tn.write("show ip route 192.0.2.1"+"\r\n")
y = tn.read_until("free", 10)
print y
tn.write("exit"+ "\r\n")
tn.close()
print "Pasul 2"
for x in range(1,99999):
m = re.search(' Known via "bgp xxxxx"', y)
if m:
print (m.group(0))
break
else:
print False
break
x has to be a number between 1 and 99999
If i write ' Known via "bgp 6447"' it will find and print it, but if i write ' Known via "bgp xxxxx"', it returns false. Anybody knows why?
The output is this:
route-views>
show ip route 192.0.2.1
Routing entry for 192.0.2.1/32
Known via "bgp 6447", distance 20, metric 0
Tag 19214, type external
Last update from 208.74.64.40 4w0d ago
Routing Descriptor Blocks:
208.74.64.40, from 208.74.64.40, 4w0d ago
Route metric is 0, traffic share count is 1
AS Hops 1
Route tag 19214
MPLS label: none
route-views>
You're using regexp in a totally wrong way, try changing the whole this section:
for x in range(1,99999):
m = re.search(' Known via "bgp xxxxx"', y)
if m:
print (m.group(0))
break
else:
print False
break
with following:
m = re.search(r'Known via "bgp \d{0,5}"', y)
if m:
print m.group(0)
else:
print False
And notice r before expression, it's important here.
Probably you should read this docs for python re module: https://docs.python.org/2/library/re.html
Upd. By the way, your version does not works because x inside string is interpreted as literal "x", not the value of variable x. If you want to put a variable inside a string you should use formatting like in this example:
x = 12345
print ' Known via "bgp {}"'.format(x)
It gives me 'True' if I test
>>> y = ' Known via "bgp xxxxx"'
>>> re.search('Known via "bgp xxxxx"', y)
>>> if x:
... print "yes"
...
yes

search and replace text inline in file in Python

I am trying to convert a file which contains ip address in the traditional format to a file which contains ip address in the binary format.
The file contents are as follows.
src-ip{ 192.168.64.54 }
dst-ip{ 192.168.43.87 }
The code I have is as follows.
import re
from decimal import *
filter = open("filter.txt", "r")
output = open("format.txt", "w")
for line in filter:
bytePattern = "([01]?\d\d?|2[0-4]\d|25[0-5])"
regObj = re.compile("\.".join([bytePattern]*4))
for match in regObj.finditer(line):
m1,m2,m3,m4 = match.groups()
line = line.replace((' '.join([bin(256 + int(x))[3:] for x in '123.123.123.123'.split('.')])),bytePattern)
print line
The portion line.replace() does not seem to be working fine. The first parameter to line .replace is working fine.(i.e it is converting the ip address into the binary format)
But line.replace doesn't seem to work. Any help or clues as to why this happens is appreciated.
with open('filter.txt') as filter_:
with open("format.txt", "w") as format:
for line in filter_:
if line != '\n':
ip = line.split()
ip[1] = '.'.join(bin(int(x)+256)[3:] for x in ip[1].split('.'))
ip[4]= '.'.join(bin(int(x)+256)[3:] for x in ip[4].split('.'))
ip = " ".join(ip) + '\n'
format.write(ip)
Why not take advantage of re.sub() instead, to both make your replacements easier and simplify your regex?
import re
from decimal import *
filter = open("filter.txt", "r")
output = open("format.txt", "w")
pattern = re.compile(r'[\d.]+') # Matches any sequence of digits and .'s
def convert_match_to_binary(match)
octets = match.group(0).split('.')
# do something here to convert the octets to a string you want to replace
# this IP with, and store it in new_form
return new_form
for line in filter:
line = pattern.sub(convert_match_to_binary, line)
print line
Your code is very odd:
line = line.replace(
(' '.join([bin(256 + int(x))[3:] for x in '123.123.123.123'.split('.')])),
bytePattern
)
The first argument is a constant that evaluates to '01111011 01111011 01111011 01111011', and bytePattern is the regex "([01]?\d\d?|2[0-4]\d|25[0-5])", so it's effectively this:
line = line.replace('01111011 01111011 01111011 01111011', "([01]?\d\d?|2[0-4]\d|25[0-5])")
This won't do anything if your file doesn't have 01111011 01111011 01111011 01111011 in it.
The .replace() method only replaces literal strings, not regexes.
If it is any help here is my old code from DaniWed IP number conversion between dotnumber string and integer with some error check added.
def ipnumber(ip):
if ip.count('.') != 3:
raise ValueError, 'IP string with wrong number of dots'
ip=[int(ipn) for ipn in ip.rstrip().split('.')]
if any(ipn<0 or ipn>255 for ipn in ip):
raise ValueError, 'IP part of wrong value: %s' % ip
ipn=0
while ip:
ipn=(ipn<<8)+ip.pop(0)
return ipn
def ipstring(ip):
ips=''
for i in range(4):
ip,n=divmod(ip,256)
print n
if (n<0) or (n>255):
raise ValueError, "IP number %i is not valid (%s, %i)." % (ip,ips,n)
ips = str(n)+'.'+ips
return ips[:-1] ## take out extra point
inp = "src-ip{ 192.168.64.544 } dst-ip{ 192.168.43.87 }"
found=' '
while found:
_,found,ip = inp.partition('-ip{ ')
ip,found,inp = ip.partition(' }')
if ip:
print ipnumber(ip)

Categories

Resources