Sommario
Questa soluzione vi permetterà di utilizzare qualsiasi di un gran numero di lingue tra cui assurdità pronunciabile con un'efficienza personalizzabile. Puoi persino creare qualcosa che sembra grammaticalmente corretto, ma senza significato inglese o francese (o peggio, qualcosa che si sposta tra i due come un poliglotta ubriaco). L'idea di base è quella di utilizzare i dati per selezionare continuamente i percorsi da una grammatica senza contesto finché non si esauriscono i dati.
dettagli
aggiungere una stringa alla fine del vostro input che non si verifica in qualsiasi punto all'interno di esso ("Questa è la fine del mio ingresso, ringrazio molto" sarebbe molto improbabile si verificano in una stringa di testo crittografato, per esempio.) Puoi farlo senza la stringa ma rende più facile.
Considera l'input come un intero molto lungo codificato a basso bit per primo. Ovviamente la tua macchina non sarà in grado di elaborare un numero intero così grande, ogni volta che avrai un byte alto zero, togli i valori del prossimo byte dal tuo file e moltiplicali.
Crea la tua lingua come context free grammar. Per evitare di dimenticare la codifica, puoi stamparla alla fine del tuo libro. Evita l'ambiguità. Se la tua grammatica è ambigua, non sarai in grado di decodificare. Questo non è difficile, in sostanza non utilizzare lo stesso terminale in due punti, assicurarsi che la concatenazione di due terminali non possa creare un altro terminale e assicurarsi che leggendo l'output si possa sapere dove si trovano i simboli di formattazione.
Ora, per prendere un numero intero e trasformarlo in linguaggio, utilizzare il seguente pseudo-codice che utilizza n per scegliere la produzione da prendere.
cur=grammar.root (cur is a list of tokens)
n=my input as one big integer
while(n > 0 || cur != grammar root){
if (cur.first.isTerminalSymbol) {
output cur.first
cur.pop_first
if(cur.isEmpty){
cur = grammar root
}
}else{
p = grammar[cur.first].number of productions
t = n mod p // t = low order digit base p
n = n div p // Shift left in base p
cur.pop_first
cur.push_first(grammar[cur.first].productionNumber[t])
}
}
Per decodificare si utilizza un generatore di parser standard come GNU bison che dovrebbe anche aiutare a evitare la creazione di una grammatica ambigua.
Eseguire il parser sull'input. Ora, avviare n a 0. È possibile ottenere il numero di produzione in ogni momento facendo riferimento alla struttura sintattica generata dal parser. Quindi moltiplicare n per il numero di produzioni e aggiungere il numero di produzione per ottenere n dopo quel particolare input. Quando si riempie il byte inferiore della parola macchina, spostarla nel file decodificato. Quando leggi la tua frase univoca, smetti di decodificare.
Esempio 1
Questo sarà più chiaro con un esempio o tre.
La mia semplice lingua di esempio è la seguente (i non-terminali sono in maiuscolo). Nota a causa delle grandi dimensioni dei terminali rispetto alla loro profondità dell'albero, non è molto efficiente ma penso che avere più terminali o renderli più brevi possa darti l'efficienza che desideri (fino al numero di bit sprecati per carattere usando n bit per carattere).
- S -> __capital Noun I-Verb Punct | __capital Noun T-Verb Noun Punct
- Noun -> joe | sally | spot | la macchina | il biscotto | il tubo
- I-Verb -> runs | vite | salti | mosche
- T-Verb -> salti sopra | mangia | cresce | giri
- Punct ->. | ! | ?
Si potrebbe facilmente fare questo con sillabe come un'espansione di verbi e nomi. Puoi anche includere frasi di parole e frasi verbali per avere aggettivi ecc. Nella tua lingua. Probabilmente vorrete anche i simboli di paragrafi e capitoli che si suddividono in sottounità appropriate con la formattazione. Il numero di scelte alternative a un certo livello dell'albero determina il numero medio di bit codificati da ciascun simbolo. __capital è un esempio di un simbolo di formattazione che, in uscita, rende maiuscola la parola successiva.
Quindi, immaginare che il mio ingresso diventa il numero 77. Poi vorrei codificarlo come segue:
S va a due cose. 77% 2 = 1. Resto 77/2 = 38.
Ora il nostro numero è 38 e stiamo espandendo __capital, Noun, T-verbo, Noun, Punct
prima parola è __capital che è un simbolo terminale . Output __capital (impostazione della routine di stampa per rendere maiuscola la parola successiva).
Ora espandendo nome. Noun ha 6 opzioni. 38% 6 = 2. 38/6 = 6. Scegliamo lo spot
Ora spot espandibile, verbo T, nome, punto. Spot è il terminale. Punto di uscita. La stampante in modalità maiuscola scrive "Spot" sul file di output.
Ora in espansione T-Verb. Il nostro numero è 6. T-verbo ha 4 opzioni. 6% 4 = 2. 6/4 = 1. Quindi scegliamo "cresce". Nel prossimo passaggio, l'output cresce nel nostro file poiché è un terminale.
Ora espandendo Noun, Punct. Noun ha 6 opzioni. Il nostro numero è 1. 1% 6 = 1 1/6 = 0. Quindi scegliamo "sally", che viene emesso nel passaggio successivo.
Infine stiamo espandendo Punct che ha 3 opzioni. Il nostro numero è 0 (e rimarrà così per sempre - è per questo che aggiungi una stringa di fine testo alla fine del tuo input, altrimenti la decodifica terminerebbe con una stringa infinita di zeri.) Scegliamo ".", che viene emesso.
Ora la stringa corrente da espandere è vuota, quindi la riportiamo alla radice "S". Ma poiché n è 0, l'algoritmo termina.
Così 77 è diventato "Spot grow sally."
Esempio 2
Le cose si fanno più efficiente se sostituisco il mio terminali con:
- I-verbo IVS _space | IVS I-verbo
- IVS IVSS vocale
- IVSS w | r
- Vocalico a | e | i | o | u | y
- T-Verb TVS _space | TVS T-Verb
- TVS TVSS vocale
- TVSS p | s
- Noun NS _space | NS
- Voce NSS NS
- NSS j | v
77 rese "Jo papa ja." sotto questa codifica (ed è veramente codificata dal proprio "Jo" e il fatto che papà ha 2 sillabe. L'extra sarebbe una piccola frazione in qualsiasi file libro-lunghezza.)
Esempio 3
L'esempio "08F734F7" è "1000111101110011010011110111" in binario, che è "1110111100101100111011110001" al contrario e cioè 250793713 in decimale.
Se corro che attraverso la grammatica più compatto, ottengo:
25079713 % 2 = 1 n=125396856, S-> __capital Noun T-Verb Noun Punct
125396856 % 2 = 0 n=62698428, Noun->NS _space-> NSS Vowel _space
62698428 % 2 = 0 n=31349214, NSS->j
31349214 % 6 = 0 n=5224869, Vowel->a
5224869 % 2 = 1 n=2612434, T-Verb->TVS T-Verb->TVSS Vowel T-Verb
2612434 % 2 = 0 n=1306217, TVSS->p
1306217 % 6 = 5 n=217702, Vowel->y
217702 % 2 = 0 n=108851, T-Verb->TVSS Vowel _space
108851 % 2 = 1 n=54425, TVSS->s
54425 % 6 = 5 n=9070, Vowel->y
9070 % 2 = 0 n=4535, Noun->NSS Vowel _space
4535 % 2 = 1 n=2267 NSS->v
2267 % 6 = 5 n=377 Vowel->y
377 % 3 = 2 n=125 Punct->?
125 % 2 = 1 n=62 S->__capital Noun T-Verb Noun Punct
62 % 2 = 0 n=31 Noun->NSS Vowel _space
31 % 2 = 1 n=15 NSS->v
15 % 6 = 3 n=2 Vowel->o
2 % 2 = 0 n=1 T-Verb->TVSS Vowel _space
1 % 2 = 1 n=0 TVSS->p
n=0 Vowel _space Noun Punct -> "a ja."
Questo produce: "? Ja pysy Vy Vo pa ja". da 08F734F7 (notare che la mia routine di stampa rimuove gli spazi prima della punteggiatura)
Quanto "plausibile" ha bisogno di guardare? Deve mostrare un'apparente coerenza sintattica in tutto il testo o essere plausibile su base frase per frase? – jball
Due bit per lettera? Questo ti lascia solo 4 opzioni valide. C'è un motivo per cui il carattere char è 1 byte. Forse 6 bit funzionerebbero, considerando che avrai 63 opzioni invece di 4. (26 minuscole + 26 maiuscole + 10 cifre = 62) –
@Charles Ray Una "lingua" che contiene quella percentuale di numeri nel testo tipico difficilmente essere plausibile Forse base26 con qualche algoritmo di capitalizzazione plausibile per la prima lettera in alcune parole. – jball