Como casar um número IP (regex)

12/dez/1999, por Aurelio Marinho Jargas

O objetivo desta página é demonstrar como elaborar uma expressão que case um número IP válido.

Um número IP válido são 4 séries de números inteiros, compreendidos no intervalo de 0 a 255 (inclusive), separados por pontos. Exemplos:

0.0.0.0
4.23.156.78
120.0.0.45
127.233.255.0
255.255.255.255

Primeiro precisamos de uma ER para casar o intervalo de números inteiros entre 0 a 255. Como o intervalo [0-255] não é valido em ERs, visto que só podemos representar intervalos entre dois caracteres, fica complicado (mas não impossível) representar este intervalo com construções regulares.

Uma primeira expressão que poderia ser alcançada poderia ser uma comprida, porém fácil de entender:

ER  : ([0-9]|[1-9][0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))
casa:   0-9 |   10-99  |  100-199  |   200-249  |250-255

Funciona, mas é pouco eficiente. E lembre-se a melhor parte de ERs é passar horas para diminuí-la um caractere que seja :) Como nos dois primeiros intervalos, de 0-9 e 10-99, temos o [0-9] comum a ambos, tendo num o [1-9] e no outro não, podemos torná-lo opcional:

ER  : ([1-9]?[0-9]|1[0-9][0-9]|2([0-4][0-9]|5[0-5]))
casa:   0-9,10-99 |  100-199  |   200-249  |250-255

Novamente, percebemos um [0-9] repetido no final dos intervalos 0-9,10-99 e 100-199. Vamos isolá-lo. SIM! É igual a matemática lá no primário! xa+xb = x(a+b)

ER  : ((1[0-9]|[1-9]?)[0-9]|2([0-4][0-9]|5[0-5]))
casa:   0-9,10-99,100-199  |   200-249  |250-255

Colorida e espaçada, para melhor entendimento:

( ( 1[0-9] | [1-9]? ) [0-9] | 2 ( [0-4][0-9] | 5[0-5] ) )

Sendo:

Branco : 1º nível de agrupamento
Amarelo: 2º nível de agrupamento (agrupamento dentro de agrupamento)
Azul   : expressão dentro do 1º nível de agrupamento
Verde  : expressão dentro do 2º nível de agrupamento


E aqui um roteirozinho esperto em Bash com o egrep para testá-la:

#!/bin/bash

a=0                                      # zerando a contagem
while [ $a -lt 300 ]                     # limitando a amostragem até 300
do echo $a |
   egrep -x '((1[0-9]|[1-9]?)[0-9]|2([0-4][0-9]|5[0-5]))'
   a=$((a+1))                            # incrementan a contagem
done

Como um ip seria quatro vezes este intervalo, separado por pontos, algo como "0-255.0-255.0-255.0-255", teríamos, no final da brincadeira o monstro que casa um IP válido:

((1[0-9]|[1-9]?)[0-9]|2([0-4][0-9]|5[0-5]))\.((1[0-9]|[1-9]?)[0-9]|2([0-4][0-9]|5[0-5]))\.((1[0-9]|[1-9]?)[0-9]|2([0-4][0-9]|5[0-5]))\.((1[0-9]|[1-9]?)[0-9]|2([0-4][0-9]|5[0-5]))

Colorida e espaçada, para melhor entendimento:

( ( 1[0-9] | [1-9]? ) [0-9] | 2 ( [0-4][0-9] | 5[0-5] ) ) \. ( ( 1[0-9] | [1-9]? ) [0-9] | 2 ( [0-4][0-9] | 5[0-5] ) ) \. ( ( 1[0-9] | [1-9]? ) [0-9] | 2 ( [0-4][0-9] | 5[0-5] ) ) \. ( ( 1[0-9] | [1-9]? ) [0-9] | 2 ( [0-4][0-9] | 5[0-5] ) )

é claro, ao programar e precisar validar um número IP com expressões regulares, estruturas e funções da linguagem de programação ajudarão nessa tarefa, como o laço e o "split".


Ou, basta chegar uma mente aberta e sugerir outra abordagem: "(0-255.){3}0-255" (valeu Wanderlei!)

( ( ( 1[0-9] | [1-9]? ) [0-9] | 2 ( [0-4][0-9] | 5[0-5] ) ) \. ) {3} ( ( 1[0-9] | [1-9]? ) [0-9] | 2 ( [0-4][0-9] | 5[0-5] ) )


Saiba mais sobre Expressões Regulares