2015-10-26 18 views
6

Voglio creare un dizionario, dove le chiavi sono espressioni regolari:È possibile utilizzare un'espressione regolare come chiave in un dizionario?

d = {'a.*': some_value1, 'b.*': some_value2} 

Poi, quando guardo nel dizionario:

d['apple'] 

voglio mela 'apple' essere confrontato con le chiavi che sono espressioni regolari. Se esiste una corrispondenza completa con una chiave/espressione regolare, è necessario restituire il valore corrispondente.

Ad esempio 'apple' corrispondenze con l'espressione regolare 'a.*' completamente, quindi some_value1 deve essere restituito.

Ovviamente, tutto ciò presuppone che le chiavi delle espressioni regolari non siano in conflitto (vale a dire che due chiavi non devono corrispondere esattamente alla stessa stringa). Diciamo che posso occuparmi manualmente di questo requisito quando costruisco le mie chiavi.

È possibile in Python? Se è così, sarebbe un costrutto piuttosto elegante e potente!

+2

* "Se è così, sarebbe molto elegante/potente costrutto!" * - No, non sarebbe, perché si può scrivere un numero illimitato di espressioni regolari che corrispondono la stessa stringa. Non stai facendo la domanda giusta. Per favore, spiega quale problema stai cercando di risolvere. – Tomalak

+2

Vuoi due cose incompatibili. Un programma non può determinare se una regex corrisponde a una stringa senza almeno guardare sia la regex e la stringa. Dato un _set_ delle espressioni regolari (le chiavi) e una stringa, l'unico modo per sapere quale regex (es) corrisponde a quella stringa è di provare ogni singola espressione regolare. Ma le prestazioni di un dizionario si basa interamente sulla sua capacità di trovare la chiave corrispondente _without_ dover scorrere tutte le chiavi. Quindi, anche se si potrebbe evitare ogni ambiguità nei vostri tasti, l'esecuzione sarebbe ancora meglio di un elenco di coppie chiave-valore. –

risposta

1

Sicuro. Basta cercarli normalmente e controllare le partite.

import re 

def find_matches(d, item): 
    for k in d: 
     if re.match(k, item): 
      return d[k] 

d = {'a.*': 'a match', 'b.*': 'b match'} 
for item in ['apple', 'beer']: 
    print(find_matches(d, item)) 

Risultato:

a match 
b match 

Nota che re.match produce solo una partita se l'espressione si trova al inizio della stringa. Utilizzare re.search se è possibile che l'espressione sia ovunque nella stringa.

3

è possibile utilizzare un modello oggetto re.compile d come chiave del dizionario:

>>> import re 
>>> regex = re.compile('a.*') 
>>> d = {regex: 'foo'} 
>>> d[re.compile('a.*')] 
'foo' 

noti che ricompilare la stessa regex ti dà una chiave uguale (lo stesso oggetto, infatti: re.compile('a.*') is d.keys()[0]), in modo da poter ottenere indietro qualunque cosa hai conservato contro di esso.

Tuttavia:

  • Come sottolineato nei commenti, molteplici espressioni regolari possono corrispondere alla stessa stringa;
  • I dizionari non sono ordinati, quindi è possibile ottenere una regex di corrispondenza diversa prima di ogni esecuzione del programma; e
  • Non c'è un modo O(1) per chiedere un dizionario {regex: result, ...} per un valore result dato una stringa che potrebbe corrispondere a una o più chiavi regex.

È quindi difficile vedere quale utilità si potrebbe trovare per questo.


Se possibile venire con un modo per garantire che non ci sono due chiavi possono corrispondere alla stessa stringa, è possibile creare un MutableMapping sottoclasse che si applica questo controllo quando si aggiungono nuove chiavi e implementa __getitem__ per eseguire la scansione attraverso le coppie chiave-valore e restituiscono il primo valore in cui l'argomento corrisponde alla regex della chiave. Anche in questo caso, questo sarebbe O(n).

5

I dizionari Python sono implementati come hash tables - il che significa che qualsiasi ricerca mydict[myvalue] è molto veloce con l'hashing interno myvalue. L'utilizzo di espressioni regolari come chiavi annullerà questa funzionalità. Invece di usare un dizionario, è necessario utilizzare un semplice elenco o tuple, dove ogni articolo è una tupla nel formato: (pattern/compiled regular expression, value) e la scansione di loro fino a quando un'espressione regolare passa. Questo vi darà anche la possibilità di giocare con l'ordine delle espressioni regolari (da specifica per genere, per esempio):

import re 

LOOKUPS = [ 
    ('a.*', 'a'), 
    ('b.*', 'b'), 
] 

def lookup(s, lookups): 
    for pattern, value in lookups: 
     if re.search(pattern, s): 
      return value 
    return None 

print(lookup("apple", LOOKUPS)) 

Vedi anche di url resolver per un (molto) implementazione avanzata della vostra idea Django.

Problemi correlati