Domanda

Sto lavorando un pezzo di codice per trasformare i numeri di telefono in link per cellulare -. Ho capito, ma ci si sente veramente sporca

import re
from string import digits

PHONE_RE = re.compile('([(]{0,1}[2-9]\d{2}[)]{0,1}[-_. ]{0,1}[2-9]\d{2}[-_. ]{0,1}\d{4})')

def numbers2links(s):
    result = ""
    last_match_index = 0
    for match in PHONE_RE.finditer(s):
          raw_number = match.group()
          number = ''.join(d for d in raw_number if d in digits)
          call = '<a href="tel:%s">%s</a>' % (number, raw_number)
          result += s[last_match_index:match.start()] + call
          last_match_index = match.end()
    result += s[last_match_index:]
    return result

>>> numbers2links("Ghost Busters at (555) 423-2368! How about this one: 555 456 7890! 555-456-7893 is where its at.")
'Ghost Busters at <a href="tel:5554232368">(555) 423-2368</a>! How about this one: <a href="tel:5554567890">555 456 7890</a>! <a href="tel:5554567893">555-456-7893</a> is where its at.'

C'è qualche cosa che potrebbe ristrutturare il regex o il metodo l'espressione regolare che sto usando per fare questo pulitore?

Aggiorna

Per chiarire, la mia domanda non è sulla correttezza del mio regex - mi rendo conto che è limitato. Invece mi chiedo se qualcuno avesse eventuali commenti per il calcolo delle substiting nei collegamenti per i numeri di telefono - c'è comunque potrei usare re.replace o qualcosa di simile che al posto del hackery stringa che ho

?
È stato utile?

Soluzione

Nizza prima ripresa :) Credo che questa versione è un po 'più leggibile (e probabilmente un po' minuscolo più veloce). La cosa fondamentale da notare qui è l'uso di re.sub . ci tiene lontano dalle brutte indici partita ...

import re

PHONE_RE = re.compile('([(]{0,1}[2-9]\d{2}[)]{0,1}[-_. ]{0,1}[2-9]\d{2}[-_.  ]{0,1}\d{4})')
NON_NUMERIC = re.compile('\D')

def numbers2links(s):

   def makelink(mo):
      raw_number = mo.group()
      number = NON_NUMERIC.sub("", raw_number)
      return '<a href="tel:%s">%s</a>' % (number, raw_number)

   return PHONE_RE.sub(makelink, s)


print numbers2links("Ghost Busters at (555) 423-2368! How about this one: 555 456 7890! 555-456-7893 is where its at.")

Una nota: Nella mia pratica, ho notato, non molto di un aumento di velocità pre-compilazione di semplici espressioni regolari come i due che sto utilizzando, anche se si sta utilizzando loro migliaia di volte. Il modulo re può avere una sorta di caching interna -. Non si preoccupò di leggere la fonte e verificare

Inoltre, ho sostituito il metodo di controllo di ogni personaggio per vedere se è in string.digits con un altro re.sub() perché penso che la mia versione è più leggibile, non perché sono certo che funziona meglio (anche se potrebbe).

Altri suggerimenti

Il tuo regexp analizza solo un formato specifico, che non è lo standard internazionale. Se ti limiti a un solo paese, si può lavorare.

In caso contrario, lo standard internazionale è ITU E.123 : "notazione per i numeri telefonici nazionali ed internazionali, indirizzi e gli indirizzi Web e-mail "

Prima di tutto, catturando in modo affidabile i numeri di telefono con una sola espressione regolare è notoriamente difficile, con una forte tendenza ad essere impossibile. Non tutti i paesi ha una definizione di un "numero di telefono", che è stretto come è negli Stati Uniti Anche negli Stati Uniti, le cose sono più complicate di quello che sembrano (dal articolo Wikipedia sul Piano di numerazione nordamericano ):

  • A) Codice del paese: il prefisso opzionale ( "1" o "1" o "001")
    • ((00|\+)?1)?
  • B) Codice Piano di Numerazione Area (NPA): non può iniziare con 1, cifra 2 non può essere 9
    • [2-9][0-8][0-9]
  • C) Codice di Borsa (NXX): non può iniziare con 1, non può finire con "11", parentesi opzionali
    • \(?[2-9](00|[2-9]{2})\)?
  • D) Codice stazione: quattro cifre, non possono essere tutti 0 (suppongo)
    • (?!0{4})\d{4}
  • E) un'estensione opzionale può seguire
    • ([x#-]\d+)?
  • S) parti del numero sono separati da spazi, trattini, punti (o no)
    • [. -]?

Quindi, l'espressione regolare di base per gli Stati Uniti potrebbe essere:

((00|\+)?1[. -]?)?\(?[2-9][0-8][0-9]\)?[. -]?[2-9](00|[2-9]{2})[. -]?(?!0{4})\d{4}([. -]?[x#-]\d+)?
| A       |S   |  |   B                | S   |   C             | S  |  D           | S  |  E      |

E questo è solo per il piano di numerazione relativamente banali della Stati Uniti, e anche lì certamente non è che copre tutte le sottigliezze. Se si vuole rendere affidabile è necessario sviluppare una bestia simile per tutte le lingue di input che ci si attende.

Un paio di cose che ripulire il regex esistente senza realmente cambiare la funzionalità:

Sostituire {0,1} con?, [(] Con ([)] con). È inoltre potrebbe anche solo rendere il vostro [2-9] B e A \ D pure, in modo da poter fare quei modelli essere \ d {3} e \ d {4} per l'ultima parte. Dubito che sarà davvero aumentare il tasso di falsi positivi.

Perché non riutilizzare il lavoro degli altri - per esempio, da RegExpLib.com ?

Il mio secondo suggerimento è quello di ricordare ci sono altri paesi oltre gli Stati Uniti, e non pochi di loro hanno telefoni ;-) Per favore, non dimenticarti di noi durante il vostro sviluppo del software.

Inoltre, v'è uno standard per la formattazione dei numeri di telefono; E.123 . Il mio ricordo dello standard è che ciò che descrive non corrisponde bene con l'uso popolare.

Edit: ho confuso G.123 e E.123. Ops. Puntelli Bortzmeyer

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top