2010-08-11 30 views
27

¿Cuál es la forma más rápida de comprobar si una cadena coincide con un patrón determinado? Es regex la mejor manera?comprobar si una cadena coincide con un patrón de dirección IP en python?

Por ejemplo, tengo un montón de cadenas y quiero comprobar cada una para ver si son una dirección IP válida (válido en este caso, significando el formato correcto), ¿es la forma más rápida de hacer esto usando expresiones regulares? O hay algo más rápido con el formato de cadenas similares o algo así.

Algo como esto es lo que he estado haciendo hasta ahora:

for st in strs: 
    if re.match('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', st) != None: 
     print 'IP!' 

Respuesta

58

Parece que usted está tratando de validate IP addresses. Una expresión regular probablemente no sea la mejor herramienta para esto.

Si desea aceptar todas las direcciones IP válidas (incluyendo algunas direcciones que probablemente ni siquiera sabía que eran válidas), puede utilizar IPy(Source):

from IPy import IP 
IP('127.0.0.1') 

Si la dirección IP no es válido lo hará lanza una excepción

O usted podría utilizar socket(Source):

import socket 
try: 
    socket.inet_aton(addr) 
    # legal 
except socket.error: 
    # Not legal 

Si realmente quiere sólo para que coincida con IPv4 con 4 partes decimales entonces se puede dividir en punto y prueba que cada parte es un número entero entre 0 y 255.

def validate_ip(s): 
    a = s.split('.') 
    if len(a) != 4: 
     return False 
    for x in a: 
     if not x.isdigit(): 
      return False 
     i = int(x) 
     if i < 0 or i > 255: 
      return False 
    return True 

Tenga en cuenta que su expresión regular no hace esta comprobación adicional. Aceptaría 999.999.999.999 como una dirección válida.

+0

Hmmm esto es perfecto. Sí, no pensé en enteros mayores que 255. –

+0

No todas las direcciones IP están en decimal. –

+0

Aceptando esto para el IPy. Terminé usando IPy en parte debido al punto de IPv6 de @ Alex. –

2

Su expresión regular no comprueba el final de la cadena, por lo que se correspondería con:

123.45.67.89abc123boogabooga 

Para corregirlo, use:

'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$' 

(nota de la $ al final)

Finalmente, en Python el estilo habitual es usar is not None en lugar de != None.

0

Puede que sea un poco más rápido compilándolo:

expression = re.compile('^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') 
for st in strs: 
    if expression.match(st): 
     print 'IP!' 
1

debe precompilar la expresión regular, si lo usa repetidamente

re_ip = re.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$') 
# note the terminating $ to really match only the IPs 

a continuación, utilizar

if re_ip.match(st): 
    print '!IP' 

pero .. es por ej. '111.222.333.444' realmente la IP?

me vería en netaddr o ipaddr bibliotecas ya sea que se pueden utilizar para que coincida con IPs

11

normalmente soy el uno de los pocos expertos en Python que firmemente se defiende expresiones regulares (tienen muy mala fama en la comunidad de Python), pero este no es uno de esos casos: aceptar (decir) '333.444.555.666' como una "dirección IP" es realmente malo, y si necesita hacer más comprobaciones después de hacer coincidir el RE, gran parte del punto de utilizando un RE se pierde de todos modos. Por lo tanto, aprovecho las recomendaciones de @Mark: IPy para mayor generalidad y elegancia (¡incluido el soporte de IPv6 si lo desea!), Operaciones de cadena y verificaciones int si solo necesita IPv4 (pero, piense dos veces acerca de esa limitación, y luego piense una más - - tiempo de IPv6 tiene manera llegado -):

def isgoodipv4(s): 
    pieces = s.split('.') 
    if len(pieces) != 4: return False 
    try: return all(0<=int(p)<256 for p in pieces) 
    except ValueError: return False 

¡Prefiero hacer eso que un RE enrevesado para que coincida con sólo números entre 0 y 256 -)

+0

+1 para el uso de 'a <= x

+0

Aunque estoy completamente de acuerdo con el punto principal de su respuesta, el código publicado aquí comprueba solo la longitud 4, mientras que las direcciones como 127.1 son válidas (socket.inet_aton acepta, y estas direcciones se pueden marcar). Esto, de hecho, fortalece la necesidad de usar módulos IPy o de socket. – 0xc0de

1

Si está validando IP! dirección Sugeriría lo siguiente:

import socket 

try: 
    socket.inet_aton(addr) 
    return True 
except socket.error: 
    return False 

Si solo quieres comprobar si está en el formato correcto, entonces querrás hacerlo para todos los legal bases (no solo para la numeración de la base 10).

Además, son la dirección IP única IPv4 (y ninguno es IPv6), entonces usted podría mirar hacia arriba lo dirección válida son y utilizar split() (para obtener individuales componentes del IP) y int() (para escribir en la casta de comparación). Una referencia rápida a las reglas válidas de IPv4 es here.

3

Uno más de validación sin necesidad de volver:

def validip(ip): 
    return ip.count('.') == 3 and all(0<=int(num)<256 for num in ip.rstrip().split('.')) 

for i in ('123.233.42.12','3234.23.453.353','-2.23.24.234','1.2.3.4'): 
    print i,validip(i) 
+0

Se deben intentar métodos como este antes de recurrir a 're'. – Dave

0

hice trampa y se utiliza la combinación de múltiples respuestas presentadas por otras personas. Creo que esto es una pieza bastante clara y directa de código. ip_validation debe devolver True o False. También esta respuesta sólo funciona para las direcciones IPv4

import re 
ip_match = re.match('^' + '[\.]'.join(['(\d{1,3})']*4) + '$', ip_input) 
ip_validate = bool(ip_match) 
if ip_validate: 
    ip_validate &= all(map(lambda n: 0 <= int(n) <= 255, ip_match.groups()) 
7

Si utiliza python3, puede utilizar ipaddress módulo http://docs.python.org/py3k/library/ipaddress.html. Ejemplo:

>>> import ipaddress 

>>> ipv6 = "2001:0db8:0a0b:12f0:0000:0000:0000:0001" 
>>> ipv4 = "192.168.2.10" 
>>> ipv4invalid = "266.255.9.10" 
>>> str = "Tay Tay" 

>>> ipaddress.ip_address(ipv6) 
IPv6Address('2001:db8:a0b:12f0::1') 

>>> ipaddress.ip_address(ipv4) 
IPv4Address('192.168.2.10') 

>>> ipaddress.ip_address(ipv4invalid) 
Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/usr/lib/python3.4/ipaddress.py", line 54, in ip_address 
    address) 
ValueError: '266.255.9.10' does not appear to be an IPv4 or IPv6 address 

>>> ipaddress.ip_address(str) 
Traceback (most recent call last): 
    File "<console>", line 1, in <module> 
    File "/usr/lib/python3.4/ipaddress.py", line 54, in ip_address 
    address) 
ValueError: 'Tay Tay' does not appear to be an IPv4 or IPv6 address 
1

Instalar paquete netaddr

sudo pip install netaddr 

Y entonces usted puede hacer esto

>>> from netaddr import valid_ipv4 
>>> valid_ipv4('11.1.1.2') 
True 
>>> valid_ipv4('11.1.1.a') 
False 

También se crea un objeto de dirección IP de esa cadena y mucho más ip operaciones relacionadas

>>> from netaddr import IPAddress 
>>> ip = IPAddress('11.1.1.1') 
>>> [f for f in dir(ip) if '__' not in f] 
['_module', '_set_value', '_value', 'bin', 'bits', 'format', 'info', 'ipv4', 'ipv6', 'is_hostmask', 'is_ipv4_compat', 'is_ipv4_mapped', 'is_link_local', 'is_loopback', 'is_multicast', 'is_netmask', 'is_private', 'is_reserved', 'is_unicast', 'key', 'netmask_bits', 'packed', 'reverse_dns', 'sort_key', 'value', 'version', 'words'] 
1

No lo hacemos necesita alguna importación para hacer esto.Esto también funciona mucho más rápido

def is_valid_ip(str_ip_addr): 
    """ 
    :return: returns true if IP is valid, else returns False 
    """ 
    ip_blocks = str(str_ip_addr).split(".") 
    if len(ip_blocks) == 4: 
     for block in ip_blocks: 
      # Check if number is digit, if not checked before calling this function 
      if not block.isdigit(): 
       return False 
      tmp = int(block) 
      if 0 > tmp > 255: 
       return False 
     return True 
    return False 
0

muy sencilla de comprobar si, dada IP es válida o no usar en la biblioteca construida ipaddress. Puede también validar utilizando el valor de máscara.

ip = '30.0.0.1' #valid 
#ip = '300.0.0.0/8' #invalid 
#ip = '30.0.0.0/8' #valid 
#ip = '30.0.0.1/8' #invalid 
#ip = 'fc00:da00::3402:69b1' #valid 
#ip = 'fc00:da00::3402:69b1/128' #valid 
#ip = 'fc00:da00::3402:69b1:33333' #invalid 

if ip.find('/') > 0: 
    try: 
     temp2 = ipaddress.ip_network(ip) 
     print('Valid IP network')   
    except ValueError: 
     print('Invalid IP network, value error') 
else:   
    try: 
     temp2 = ipaddress.ip_address(ip) 
     print('Valid IP') 
    except ValueError: 
     print('Invalid IP') 

Nota: Probado en Python 3.4.3

0

Esto funciona para direcciones IPv6 también.

Desafortunadamente funciona para python3 sólo

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') 
0

Otras respuestas de expresiones regulares en esta página aceptará una IP con un número superior a 255.

Esta expresión regular evitará este problema:

import re 

def validate_ip(ip_str): 
    reg = r"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" 
    if re.match(reg, ip_str): 
     return True 
    else: 
     return False 
0
#!/usr/bin/python 
import sys 
def check_ip(address): 
    part=address.split(".") 
    temp=True 
    if len(part) != 4: 
      temp=False 
      return temp 
    for p in part: 
      if not 0<= int(p) <= 255: 
        temp=False 
        return temp 
      else: 
        temp=True 
    return temp 
if __name__=="__main__": 
    print check_ip(sys.argv[1]) 

Guarde el código con un nombre que diga- check_ip.py y ejecútelo como python check_ip.py 192.168.560.25
Nota: - Por encima de código de falla para la dirección IP- continuación
023.65.029.33

+0

¿Este código funciona en Windows? 'Archivo" C: \ Python \ Codes \ check_ip.py ", línea 17 imprimir check_ip (sys.argv [1]) ^ SyntaxError: sintaxis no válida' – Sabrina

Cuestiones relacionadas