2009-05-14 17 views
6

Questo problema è simile alle iniezioni SQL cieche. L'obiettivo è determinare il valore esatto di una stringa, e l'unico test che puoi fare è vedere se un carattere jolly in stile DOS (? = Qualsiasi carattere, * = qualsiasi numero di caratteri) specificato viene abbinato alla stringa. (Quindi praticamente hai solo accesso a una funzione bool DoesWildcardMatch(string wildcard)).Il modo più veloce per forzare una stringa usando un carattere jolly DOS

Il modo semplice è di testare a*, b*, c*... fino a trovare la prima lettera, quindi ripetere. Alcune ottimizzazioni mi viene in mente:

  • set
  • quando viene trovata una corrispondenza su *x* ricerca di *a*, *b* ecc per determinare il carattere, eseguire divide-et-impera (*a*x*, *b*x*, ...)
+0

Alcune varie domande sulla stringa: che cosa può essere il set di caratteri? Solo lettere o altri caratteri sono autorizzati a? Quanto può durare la stringa? La materia inferiore/maiuscola? – schnaader

+0

Non capisco davvero come queste informazioni possano aiutarvi a trovare un algoritmo efficiente, ma dal momento che avete chiesto - nel mio caso particolare, la stringa è un hostname su Internet, quindi è alfa-numerics e alcuni simboli come. e -. –

+0

L'involucro non importa -? corrisponde esattamente a un simbolo, * corrisponde a zero o più simboli, e ogni altro simbolo corrisponde esattamente a quel simbolo (se non fa distinzione tra maiuscole e minuscole, puoi considerare i simboli minuscolo e maiuscolo uguali). Anche l'alfabeto non ha importanza (eccetto forse come gestire? E * nell'alfabeto). Interessante potrebbe essere se ci sono delle ipotesi sulla dimensione dell'alfabeto, la lunghezza della corda, le frequenze dei simboli o il rapporto tra la dimensione dell'alfabeto e la lunghezza della corda. –

risposta

2

Un primo pensiero. È possibile determinare la lunghezza n della stringa in O(log2(n)).

  • check Z* dove Z rappresenta k punti interrogativi a partire da 0, 1, e poi raddoppiando il numero di punti interrogativi con ogni controllo finché non si verifica alcuna corrispondenza. n deve essere compreso tra k/2 e k
  • Trova la lunghezza esatta utilizzando lo stesso modello modificando k nello stesso modo della ricerca binaria.

Conoscere la lunghezza esatta potrebbe aiutare a eseguire una sorta di divide-et-impera nel dominio spaziale.

UPDATE

Se si conosce la lunghezza, è possibile utilizzare lo stesso modello per individuare correttamente un simbolo.

Esempio:

 
    ..X. ..XX (spaces added for readability) 

           + symbol may be X 
           - symbol is not X 
           X symbol is X 

    *X*   => MATCH  ++++ ++++ 
    *X* ???? => MATCH  ++++ ++++ 
    *X*?? ???? => NO MATCH --++ ++++ 
    ??X? ???? => MATCH  --X+ ++++ 
    ??XX ???? => NO MATCH --X- ++++ 
    ??X? *X*?? => NO MATCH --X- --++ 
    ??X? ??X? => MATCH  --X- --X+ 
    ??X? ??XX => MATCH  --X- --XX 

Per la lunghezza n e alfabeto stringa di formato m questo richiederà circa O(log2(n)) per trovare la lunghezza della stringa, circa O(n • log2(n)) per posizionare correttamente n simboli, e O(m) per trovare i simboli usati - sommando tutti insieme produce O(n • log2(n) + m).

Posso immaginare che sia possibile accelerare unendo diversi passaggi, magari testare i simboli usati mentre si determina la lunghezza della stringa o contemporaneamente localizzare due (o anche più?) Simboli nella prima e nella seconda metà della stringa . Ciò richiederà di ricontrollare i passaggi uniti separatamente se il controllo fallisce al fine di determinare quale controllo fallire. Ma finché il controllo unito riesce, ottieni informazioni su entrambi.

Forse lo calcolerò domani per vedere se accelera davvero la cosa.

+0

Vediamo. Se abbiamo un alfabeto di dimensione m e stringhe di dimensione fissa n, allora una stringa contiene n * log (m) bit di informazione. Ogni query può ottenere al massimo 1 bit di informazioni. Quindi hai bisogno di almeno O (n log (m)) query. Questo può essere maggiore di O (n log (n) + m). Quindi la tua risposta deve essere sbagliata. – Accipitridae

+0

No, l'ho pensato anch'io. Ma possiamo ottenere più di un bit per assegno. Ad esempio, se * A * fallisce, sappiamo che nessuno dei simboli n è uguale ad A e abbiamo ottenuto più di un bit di informazione con un singolo controllo. –

+0

Più precisamente dipende dalla lunghezza della stringa quante informazioni sono state ottenute. Un controllo * A * in difetto riduce lo spazio di ricerca da m^n a (m - 1)^n, quindi da n * log2 (m) a n * (log2 (m - 1)) bit. Per n> 1/log2 (m/m - 1) otteniamo più di un bit di informazione. Nel caso di m = 26 questo richiede n> 18. –

1

Se un numero specifico di? funziona, puoi anche controllare "?", "??", "???" ecc. per ottenere la lunghezza della corda, ma dubito che ciò sarà di grande aiuto in quanto puoi anche controllare se hai la lunghezza giusta con un solo controllo aggiuntivo senza caratteri jolly dopo ogni round.

penso che il metodo divide con un assegno set di caratteri prima è quasi ottimale, ci sono alcuni dettagli aggiuntivi, ad esempio se si abbinato *a*b*, si dovrebbe verificare *ab* successivamente per sapere se ci sono lettere in mezzo e, naturalmente, come dichiarato sopra, controllare *ab e "ab" dopo questo per sapere se hai finito sul lato destro o completamente.

0

Perché non convertire la stringa di caratteri jolly in stile DOS in un'espressione regolare? ? Es .:

un *

diventa:

.a *

Poi basta eseguire una semplice partita di espressione regolare a confronto che, per la stringa di prova..

+0

Mi dispiace, ma non capisco come le espressioni regolari possano aiutare a risolvere questo problema. Dal punto di vista del codice, immagina di poter chiamare solo una funzione che accetta un carattere jolly DOS e restituisce un valore booleano che indica se la stringa che dobbiamo determinare corrisponde al carattere jolly specificato. Non possiamo testare la stringa sconosciuta con un'espressione regolare. –

2

Per quanto riguarda il divide-et-impera, assicurarsi di tenere traccia del valore che si conosce non sono presenti. Inoltre non andrei con a, b, c, ma con ordine di frequenza. Una sorta di catena del markov potrebbe renderlo ancora più veloce.

Una cosa a cui prestare attenzione è che non si può presumere che un dato letterale corrisponderà sempre alla stessa posizione nell'input. Questo sarà di particolare interesse per quanto riguarda la rimozione delle jolly alla fine.

c a b a 
-------- 
* a *  match 
    * b*a* woops! 
+0

Per quanto riguarda la frequenza - sì è ovvio, ho appena dimenticato di dirlo. Un buon punto sul divide et impera. –

Problemi correlati