2012-02-24 13 views
5

Quindi questo è un caso ovvio di "stai facendo male". In realtà non intendo farlo, ma una conversazione al lavoro ha sollevato questa domanda:Utilizzo di espressioni regolari per confrontare i numeri

È possibile generare un'espressione regolare per determinare se un numero intero è inferiore a un valore arbitrario.

Per alcuni valori questo è facile. Per numeri interi inferiori a 1000, \ d {1,3} dovrebbe fare il trucco. Per gli interi < 500, è un po 'più complicato, ma non così male, dato che puoi usare [0-4] {0,1} \ d {1,2}.

Una volta arrivati ​​a valori arbitrari, diventa molto più complicato. Ad esempio, tutti i numeri inferiori a 255 sarebbero qualcosa come \ d {1,2} | [0-1] \ d {2} | [2] [0-4] \ d | [2] [5] [0-4].

C'è una singola espressione regolare che funziona qui? O devi generare in modo programmatico la regex?

(E di nuovo, mi permetta di sottolineare che non ho alcuna intenzione di fare questo. Ovviamente usando "foo < bar" nel linguaggio di programmazione preferito è molto più efficiente e di facile lettura.)

+0

è possibile combinare le tre espressioni si deve ottenere uno solo, se è questo che vuoi dire. – Dervall

risposta

3

You' avremo bisogno di generare l'espressione per ogni numero limite. Diciamo che c'era un'espressione regolare che avrebbe fatto il lavoro. Quindi quell'espressione regolare dovrebbe essere in grado di prendere come input una sequenza di caratteri. Tuttavia, sappiamo che le espressioni regolari e gli automi a stati finiti sono equivalenti, quindi equivale a dire che possiamo costruire un FSM poiché il numero possibile è illimitato, che richiederebbe un numero illimitato di stati, che contraddice la definizione di FSA.

+0

Eh? Stai dicendo che non può essere fatto, o è un modo davvero divertente di dire si? Stai alludendo ai numeri negativi, anche se l'OP indica chiaramente uno spazio numerico non negativo? – tripleee

+0

Non può essere fatto. Non puoi scrivere un'espressione regolare che, in generale, ti dirà se un numero arbitrario è maggiore di un limite arbitrario, perché non sono finiti. –

+0

Se OP significa solo un numero particolare, può farlo banalmente: enumera tutti i valori sotto il suo limite. Quindi, se si sente ambizioso, ridurre al minimo l'FSM corrispondente e utilizzare la regex minima. –

2

Questo è abbastanza facile.

#!/usr/bin/env perl 
use strict; 
use warnings; 
use Regexp::Assemble; 

for my $n (@ARGV) { 
    my $asm = new Regexp::Assemble; 
    for (1 .. $n) { $asm->add($_) } 
    for ($asm->re){ 
     s/\)$/\$/; 
     s/^[^:]*:/^/; 
     print "$n => /$_/\n"; 
    } 
} 

Ora eseguirlo per trovare il modello che corrisponde numeri interi compresi tra 1 e che il numero:

$ perl /tmp/ra 5 15 153 401 1144 
5 => /^[12345]$/ 
15 => /^(?:[23456789]|1[]?)$/ 
153 => /^(?:1(?:[6789]|5[0123]?|0\d?|1\d?|2\d?|3\d?|4\d?)?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)$/ 
401 => /^(?:1(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|2(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|3(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|4(?:[123456789]|0[01]?)?|5\d?|6\d?|7\d?|8\d?|9\d?)$/ 
1144 => /^(?:1(?:0(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|1(?:[56789]|4[]?|0\d?|1\d?|2\d?|3\d?)?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|2(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|3(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|4(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|5(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|6(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|7(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|8(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|9(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?)$/ 
Problemi correlati