Newsgroup: it.comp.www.php
Titolo: Parsing numeri di telefono

Avete qualche idea su come creare un'espressione regolare che estragga 
i numeri di telefono da una testo più o meno esteso?
Diciamo che le tipologie che si possono presentare sono molteplici.
Esempi:
"Ecco il mio numero di telefono: 349 1234567"
"Ecco il mio numero di tel.: 349 1234567"
"Ecco il mio numero di tel. 349 1234567"
"Ecco il mio numero di tel: 349 1234567"
"Ecco il mio numero di cellulare: 349 1234567"
"Ecco il mio numero di cellulare 349 1234567"
"Ecco il mio numero di cell.: 349 1234567"
"Ecco il mio numero di cell: 349 1234567"
"Ecco il mio numero di cell. 349 1234567"
"Ecco il mio numero di cell 349 1234567"
"Ecco il mio numero di cel.: 349 1234567"
"Ecco il mio numero di cel: 349 1234567"
"Ecco il mio numero di cel. 349 1234567"
"Ecco il mio numero di cel 349 1234567"
(questo era per la parola prima del numero vero e proprio)
Per quanto riguarda il numero vero e proprio, può esserci scritto:
"349 1234567"
"(349) 1234567"
"3491234567"
"349/1234567"
"349\1234567"
"349-1234567"
(ovviamente il prefisso non è sempre 349, e la lunghezza del prefisso o 
del numero non è sempre la stessa per tutti quanti! :))
Per non parlare che potrebbero anche essere scritti due numeri di 
telefono uno accanto all'altro, tipo:
"349 1234567 - 
347 7654321
"
(e tutte le altre combinazioni di sopra)
Ecco....prima di spararmi o chiudermi in manicomio, qualcuno di voi ha 
già affrontato un problema simile, o sa come destreggiarsi in tal caso?
Io per ridurre la casistica, avevo pensato di rimuovere preventivamente 
ogni carattere che non sia un numero. Solo che in questo caso, sarei 
fottuto quando ho due numeri di telefono consecutivi (come nell'ultimo 
esempio).
Idee??
-- 
rob4you

rob4you wrote:

mah.. io preferirei chiedere direttamente all'utente di inserire valori
facilmente estraibili..
comunque non testato e senza controllo degli errori..
function extract_numbers ($string, $maxPartLen = 12, $maxSpaceLen = 3)
{
        $pattern = "/(?:[0-9]{1,$maxPartLen}[^0-9]{0,$maxSpaceLen})+/";
        preg_match_all($pattern, $string, $matches);
        $result = array();
        foreach ($matches[0] as $number)
                $result[] = preg_replace('/[^0-9]/', '', $number);
        return $result;
}
sembrerebbe funzionare in gran parte.. anche con piu' numeri.. ma spero che
ne intuirai i limiti..
-- 
www.iuz-lab.info
 - 
www.php-faq.org

 "349-1234567"
Per esperienza personale, se utilizzi un campo per l'inserimento del
numero troppo ampio gli utonti ti stupiranno dalle mille interpretazioni
differenti.
Dividi almeno in due il campo con il primo utilizzato come prefisso a
spazi fissi e a fianco una descrizione (o un menu a tendina con tutti i
prefissi, ma lo trovo troppo limitato).
Il numero vero e proprio non è che possa essere poi tanto di lunghezza
differente.
Prima di inserirlo controlla che sia, prima di tutto, un numero e non 2
o 3 (1234 567 89 non va bene).
Elimina tutti i caratteri non numerici e gli spazi successivamente.
A questo punto vedi se la lunghezza del numero è maggiore di 5 (non
maggiore di 9999 ma proprio la lunghezza).
A questo punto hai una buona possibilità di inserire un numero di
cellulare reale.
-- 
Amministratore
www.amiciamici.com
Giornalismo dal basso sull'amicizia e sul turismo
"Pronto Chi Bussa" il primo podcast di Parma e provincia?

 differenti.
Il problema è che non sono io che creo un form in cui inserire un 
numero di telefono e quant'altro, altrimenti ovviamente mi metterei 
nella situazione più comoda per me. :)
Quel numero di telefono è presente in un annuncio. Immagina l'utente 
che pubblica un annuncio su una rivista specializzata:
"Vendesi notebook di pochi mesi 80 Gb di Hard Disk 2 Gb di Ram vari 
software installati - vendesi € 500 - tel. (0434) 241921."
A partire da questo annuncio, tra le altre cose da fare, vorrei appunto 
estrarre il numero di telefono.
La difficoltà è che, essendo mille teste diverse quelle che scrivono 
gli annunci, avrò potenzialmente mille maniere diverse di leggere il 
numero di telefono.
Solo che io, essere umano, riuscirò a capire sempre e comunque quale è 
il numero telefonico, invece sarà più difficile riuscire a farlo capire 
a un computer. Ma ci devo provare. :)
Considera che molti siti hanno la possibilità di inviare l'annuncio da 
pubblicare via sms, quindi l'utente lo inserisce tutto di fila, senza 
alcun form da compilare.
Secondo te è possibile? Ok, non la copertura del 100% degli annunci, ma 
almeno ci si può avvicinare? Cavolo dico io....l'uomo ci riesce, perché 
il computer no! LOL
-- 
rob4you

 ne intuirai i limiti..
Appena posso dò un'occhiata, cercando di capirne i punti di debolezza. 
:)
Se hai altre idee ovviamente sono ben accette! LOL
-- 
rob4you

 il computer no! LOL
Io partirei con il rintracciare nel codice che prelevi uno dei possibili
prefissi di telefonia mobile italiana (che non sono poi tantissimi).
Se lo trovi prendi 10 caratteri dopo, ne elimini gli spazi, le
parentesi, i trattini e vedi in quanti casi hai dei dati puliti e corretti.
Scusami ma di codice non ho il tempo di scriverne.


 Scusami ma di codice non ho il tempo di scriverne.
Forse mi sono espresso male io: il numero di telefono non 
necessariamente è un cellulare, può benissimo essere un numero fisso.
Per assurdo potrebbe anche essere un numero internazionale!
La cosa che dico io è che, da uomo, riuscirò sempre e comunque a capire 
quale sia il numero di telefono. Ora mi domando, è possibile addestrare 
il computer a fare lo stesso?
-- 
rob4you

rob4you wrote:

non e' che ti stai buttando in qualcosa piu' grande di te?
dalle tue ultime domande sembra che tu stia cercando di creare un sistema
intelligente per l'estrazione di dati da annunci di vario tipo.. nel mio
piccolo posso dirti che i sistemi esperti falliscono spesso.. io mi
butterei su piccole intelligenze artificiali come le reti neuronali.. ma in
questo caso abbandonerei PHP per quanto riguarda l'elaborazione e passerei
a qualcosa di piu' basso livello..
tirando le somme.. se non vuoi sbatterti troppo nell'istruire reti
neuronali.. e se non hai a disposizione grandi capacita' elaborative..
scrivi qualche semplice algoritmo per individuare i numeri telefonici..
in fondo non sarebbe difficile.. 
cerca il primo carattere numerico nel testo..
se e' seguito da altri caratteri numerici "collezionali" altrimenti
scartali..
se i caratteri non numerici scartati sono piu' di 2 (in sequenza) il numero
e' finito altrimenti continua a "collezionare" numeri..
se il numero finito e' composto da meno di 8 caratteri non e' valido
altrimenti memorizzalo..
ricomincia da capo..
certo che messo in questo modo sembra un mezzo sistema esperto.. e comunque
il codice che ti ho scritto e' in grado di ottenere gli stessi risultati..
parlando da profano di AI.. quindi prendi quello che ti ho detto con delle
grandi ed allenate molle..
-- 
www.iuz-lab.info
 - 
www.php-faq.org

rob4you ha scritto:

Prima di tutto io mi chiederei quali sono i parametri che ti fanno dire,
da uomo, che quello è un numero di telefono.
Elencali e procedi ad eliminare dal testo tutto quello che non rientra
nei parametri.
L'impresa, però, per la moltitudine di possibilità e di variabili in
gioco non è semplice.
Per esempio, io scrivo sempre il mio cellulare o numero di telefono in
gruppi di 2 o al massimo 3 cifre (0123 12 34 567) per renderlo
maggiormente leggibile ed "imparabile".


 il codice che ti ho scritto e' in grado di ottenere gli stessi risultati..
Riguardo il caso specifico del numero di telefono, cercherò di 
considerare con attenzione le cose che mi hai suggerito.
Se funzionano (come alla fine dovrebbero), ciò vorrà dire che PHP 
continua a fare fantasticamente il suo dovere. :)
-- 
rob4you

 gioco non è semplice.
E' esattamente ciò che io cercavo di dire nel mio primo post. :)
Ma.....non a caso......IMPOSSIBLE IS NOTHING. LOL
Con calma, magari seguendo i suggerimenti di iuz, vedrò di lavorarci un 
po' su, per ottenere un risultato concreto.
I problemi penso dovrebbero essere solo quando sono presenti piu di un 
numero telefonico. Ma vedremo come fare.
Come sempre...ogni idea è ben accetta! ;)
-- 
rob4you

 Come sempre...ogni idea è ben accetta! ;)
elenca tutti i modi in cui tu pensi che si possa scrivere un numero di
telefono. crea la regex che li matchi tutti. dai il programma in pasto
ai malvagi utenti. questi sicuramente troveranno altri modi per scrivere
il numero di telefono: ogni volta che ne trovi uno, fa' in modo che la
regex comprenda anche questi modi (un algoritmo che autoapprende sarebbe
eccezionale e divertente da implementare).
in questo modo, la possibilità di errore diminuirà esponenzialmente e
quando sarai arrivato "a regime", ci sarà solo un fallimento ogni N
numeri, con N >> 1. ovviamente N dipende dalla criticità del sistema.
tempo fa sviluppai una cosa del genere: ad ogni fallimento mi veniva
inviata un'email ed io agivo manualmente nel db e aggiornavo il codice
per comprendere anche quella nuova eccezione (ed anticipavo eventuali
altre dello stesso genere).
Ciao, Maverick
-- 
«Che non siete più liberi di non avere una casa con letto per dormire.
 Lavorate voi - schiavi dei soldi - che non sentite la puzza della
 schiavitù!» (a Mario di Monte Mario, Roma) # 
http://libre.netsons.org/

 telefono. crea la regex che li matchi tutti. dai il programma in 
Secondo me il problema grosso non e` trovare tutti i modi per scrivere 
un numero di telefono. Il problema e` capire quale parte del testo e` 
un numero di telefono, e dove finisca.
Se ci fosse un campo SOLO per il numero di tel, basterebbe toglierci 
tutti i caratteri che non siano numeri o "+" (per il prefisso 
internazionale).
Ma se hai "vendo 40 scatole da 23 mele. +39-123-45.67.89 dalle 19 alle 
20" sei fregato.
Puoi cercare di estrapolarlo prendendo come "boundaries" le lettere 
alfabetiche, poi arriva uno che scrive "vendo 40 scatole da 23 mele. 
+39-(123)-45.67.89 (7-8 di sera)".
E allora ti devi scrivere un parser e crearti una grammatica di 
linguaggio. Buona fortuna! :)
Oppure fai presente al cliente che l'algoritmo funziona nel 90% dei 
casi, e per raggiungere il 100% il costo decuplica perche` devi farti 
una specie di A.I. solo per recuperare i numeri di telefono.
Bye.

 20" sei fregato.
Scusate ma questa cosa non la fa già skype? Se attivi la funzione quasiasi documento web uno apre
skype riesce ad intercettare il numero e lo sostituisce con una sua iconcina che consente di fare la
chiamata.
Ciao Stefano

 sostituisce con una sua iconcina che consente di fare la chiamata.
E' vero? uhm...mi sa che mi installo il plugin di skype per vedere come 
si comporta con tutti le migliaia di annunci che ho. :)
-- 
rob4you

 20" sei fregato.
Hai capito infatti quale è il vero problema.
Tra l'altro, anche con l'uso massiccio di regexp, talvolta mi sembra di 
intravedere che si possa risolvere qualcosa, ma a scapito di un'altra.
Mah, vedremo che si può fare.....e in che percentuale il risultato sarà 
affidabile. :)
-- 
rob4you

rob4you wrote:

beh.. avrei trovato questo documento..
http://www.agcom.it/provv/d_09_03_CIR.htm
bisogna anche vedere quali numeri ti prefiggi di coprire..
i formati dei numeri che dovresti cercare sembrano essere..
non testata e probabilmente non funzionante..
/((\+|00)?([0-9]{2}))?[03][0-9]{11}/
penso che con questo formato prenderesti anche i numeri di san marino e
vaticano ma dovresti provare..
naturalmente dovresti utilizzare questa regex per validare numeri gia'
estratti (magari col codice che ti avevo postato in precedenza
e "leggermente" modificato)..
-- 
www.iuz-lab.info
 - 
www.php-faq.org

 linguaggio. Buona fortuna! :)
Basta semplicemente aggiungere quel formato, fingendo che tutto il resto
che non è un numero di telefono non esista, e la prossima volta che
qualcuno userà quello stesso formato, l'algoritmo non fallirà.
Nel caso in questione, il problema nasce "solo" con i numeri presenti
nella stringa che siano di una lunghezza compresa tra quella minima e
massima ammissibile. Nella esempio che ho fatto io, è impossibile
discriminare tramite regex tra numero del cliente e numero di cellulare.
Nella grande maggioranza dei casi, però, un numero di telefono è facile
da individuare (come detto, ci sono delle parti semi-fisse), mentre nei
restanti casi è necessario l'intervento umano: una specie di controllo
qualità, come avviene nelle fabbriche (lavoro tipicamente femminile :P).
Controllo che può anche essere lasciato all'utente finale ("scusi, ma il
numero per contattarla è 338... oppure 339...?"), se l'applicazione è
interattiva (non mi sembra sia questo il caso).
Ciao, Maverick

 imperfetta) solo con qualche algoritmo di AI.
Questa si che è una bella rogna.
Ma come fa un uomo a capire che il primo non è un numero di telefono e 
il secondo si?
IN questo caso è semplice, perché è scritto: "il mio CELL: è".
Quindi in tal caso, senza scomodare l'AI, basterebbe controllare se 
prima del numero ci sia scritto qualcosa tipo:
"il mio numero è, il mio cel, chiamatemi al, sono reperibile al, ecc.".
Mi rendo conto che comunque la cosa diventa sempre, ma sempre più 
complessa, come sospettavo del resto! LOL
Però sarebbe effettivamente un bel passo avanti riuscire a farlo. :)
Il problema che aveva segnalato alessandro non è comunque banale:
"vendo 40 scatole da 23 mele. +39-(123)-45.67.89 (7-8 di sera)"
Con questa stringa, tu magari dici che effettivamente sarebbe possibile 
escludere il "(7-8) dal numero.
Ma immagina che ci fosse scritto:
"vendo 40 scatole da 23 mele. +39-(123)-45.67.89 (7-8)"
In questo caso la cosa diventa ben più difficile da discernere 
(potrebbe trattarsi di una coppia di numeri telefonici (che terminano 
con 7 o con 8), oppure della fascia di orario in cui chiamare. Ma mi 
rendo conto che effetivamente forse non sarebbe un problema cosi 
grande, visto che una tale rappresentazione sarebbe di difficile 
comprensione anche per un uomo. :)
Non so se è una boiata, ma l'idea di eliminare preliminarmente tutta la 
punteggiatura potrebbe essere un punto di inizio non da buttare, anche 
se ci sono i rovesci della medaglia.
Fermo restando le idee di iuz che sono davvero ottime, e ci indagherò 
su. LOL
-- 
rob4you

 su. LOL
la smetti di lollare? :P


 e "leggermente" modificato)..
La funzione che avevi postato in effetti, ocn piccolissime modifiche, 
risolve numerosi casi.
Ma non riesco a capire come risolvere una cosa: nella stringa completa 
che gli passo possono esserci, oltre ai numeri di telefono, anche altri 
numeri. Per quelli di lunghezza piccola (tipo 4, 6 cifre al massimo) li 
posso filtrare tranquillamente con un controllo strlen sui matches.
Ma quando ho un numero di lunghezza confrontabile con la lunghezza di 
un numero di telefono, come la filtro?
Esempio:
"questa casa costa 40.000.000,00 di euro. Tel. 3491234567"
Hanno tutti e due lunghezza dieci cifre.
Avevo pensato di inserire nella regexp, un controllo sulla parola 
antecedente al numero vero e proprio: controllare cioè se prima del 
numero c'è "tel., cel, ecc.".
Solo che data l'espressione che mi hai suggerito tu, che riscrivo qui 
sotto:
$pattern = "/(?:[0-9]{1,$maxPartLen}[^0-9]{0,$maxSpaceLen})+/";
Non basta aggiungere in testa "tel." (magari col modificatore 
case-insentive), perché non va bene se scrivo qualcosa del tipo:
"questa casa costa 40.000.000,00 di euro. Tel. (349) 1234567"
In quanto non trova dopo il "tel." una cifra, ma una parentesi.
Come si può risolvere secondo te? Eliminando preventivamente ogni 
punteggiatura? Oppure c'è una regexp che può farlo più comodamente?
-- 
rob4you

 "questa casa costa 40.000.000,00 di euro. Tel. (349) 1234567"
Tra l'altro l'ultima cosa che ho detto non va manco tanto bene, quando 
si tratta di due numeri:
"questa casa costa 40.000.000,00 di euro. Tel. (349) 1234567 - 
3331234567"
Prima del secondo numero telefonico non c'è la parola "tel" (o simili).
UFFAA..ma io loho detto...si aggiusta una cosa e se ne rovinano altre! 
:)
A questo punto dovrei isolare PRIMA il prezzo (tra l'altro l'estrazione 
del prezzo mi interesserebbe pure ;) ),  e poi operare sul resto.
-- 
rob4you

rob4you wrote:

un sistema sicuro non c'e' a meno che tu non ceda a sistemi molto piu'
complessi..
comunque per i numeri di telefono puoi sempre cercare di validare il numero
come ti ho spiegato in qualche post precedente..
40.000.000,00 non puo essere un numero valido perche' inizia con un 4.. e
cosi' via..
-- 
www.iuz-lab.info
 - 
www.php-faq.org

 case-insentive), perché non va bene se scrivo qualcosa del tipo:
[..]
bisogna vedere come hai modificato la regex.. cosa hai aggiunto di preciso?
-- 
www.iuz-lab.info
 - 
www.php-faq.org

 bisogna vedere come hai modificato la regex.. cosa hai aggiunto di preciso?
A dir la verità non ricordo precisamente, perché se lasciavo 
l'aggiunta, non mi prendeva più i numeri doppi di telefono.
Comunque mi sa che avevo fatto qualcosa banale del tipo:
$pattern = 
"/tel[^0-9]+(?:[0-9]{1,$maxPartLen}[^0-9]{0,$maxSpaceLen})+/";
Ma a quel punto, in una stringa del tipo:
"... tel. (0432) 502928 - 338. 6624804."
Mi prendeva il primo numero, ma il secondo no.
E quindi ho riporato all'inizio.
In più ho fatto in modo che se la lunghezza è minore di 8 cifre, allora 
scarto il numero, viceversa lo prendo.
In tal caso però, come dicevo, mi restava il problema del prezzo, che 
può tranquillamente essere anche di 8-10 cifre.
E la validazione non potrebbe andare sempre bene, esempio:
"Vendo a euro 32.050.500,00. tel. (0432) 502928 - 338. 6624804."
La discriminante in tal caso è la parola "euro" per il prezzo, e la 
parola "tel." per il numero telefonico (o almeno per il primo numero 
telefonico, l'altro è a seguire).
-- 
rob4you