i dizionari di NVDA, seconda parte

i dizionari di NVDA, seconda parte
Di Adriano Barbieri.
********
Nel precedente articolo dedicato all'argomento abbiamo visto come far matchare, cioè riconoscere, una determinata parola, "vocabolo", inserito in uno dei tre dizionari messi a nostra disposizione dallo Screen-reader NVDA.
Abbiamo verificato tramite esempi pratici come far matchare un vocabolo interamente in maiuscolo/minuscolo, e a prescindere dall'avere l'iniziale maiuscola/minuscola.
Questo grazie all'uso delle Regular Expressions o comunemente chiamate Regex.
Per ottenere questo risultato abbiamo utilizzato solamente due caratteri speciali:
• "|", La barra verticale, operatore logico "or", che ci permette una alternativa ed è come dire letteralmente: "oppure".
• "[]", le parentesi quadre, che ci permettono di definire una classe di caratteri a nostra discrezione, dandoci anche modo di delimitare un "Range" (serie), grazie all'uso del carattere speciale "-" (Trattino).
L'esempio dell'articolo precedente, tanto per rinfrescarci la memoria era un semplice nome di persona: "Sophia".
La Regex usata era: "SOPHIA|[sS]ophia", attenzione che le virgolette servono solo a racchiudere gli esempi.
Tradotta in parole è come aver detto al modulo dizionario: se SOPHIA è in maiuscolo oppure una iniziale che ho racchiuso fra parentesi quadre corrisponde nonché il resto in minuscolo della parola corrispondono, allora il confronto è "true" (cioè vero), quindi, sostituisci il matching con la parola che trovi nel campo voce in sostituzione: "sophìa".
La sintassi è valida nella maggior parte dei vocaboli in cui ci imbatteremo durante la lettura di qualsiasi testo e può essere applicata indipendentemente dalla sintesi vocale in uso.
Nell'articolo precedente v'è anche stilata una lista dei caratteri speciali che possono essere applicati a seconda del risultato che si desidera raggiungere, alcuni sono composti da semplici lettere in maiuscolo o in minuscolo ma sono sempre preceduti dal carattere: "\"(barra diagonale rovesciata, detta anche controbarra).
Opportunamente combinati, questi caratteri speciali ci consentono di ottenere risultati di gran lunga superiori rispetto ai diversi sistemi comunemente adottati da altri Screen-reader.
Alcuni di questi, ci mettono a disposizione un carattere speciale "*", asterisco, che, se posto a destra di un vocabolo, permette di matcharlo anche se composto da caratteri misti attigui, però, senza possibilità di scelta, e soprattutto non bilateralmente.
La domanda che sorge spontanea a questo punto è: "Con NVDA posso fare altrettanto?".
La risposta è: "Anche di meglio!".
Infatti, possiamo crearci il nostro "asterisco" personale; Grazie all'uso delle parentesi tonde, di un carattere speciale "\" (barra diagonale rovesciata, detta anche controbarra), e vedremo un altra utile sua funzione.
Abbiamo già appurato nell'articolo precedente, come quest'ultimo carattere messo a sinistra di un altro possa assegnare o togliere proprietà di carattere speciale o ridurlo al suo semplice significato letterale.
Ora vedremo un'altra peculiarità ad esso abbinata, e cioè quella di poter richiamare e conseguentemente far vocalizzare alla nostra sintesi una o più parti dei risultati elaborati e memorizzati nelle rispettive espressioni racchiuse fra parentesi tonde che possono essere presenti in una stringa Regex.
Ogni gruppo di queste espressioni ha un numero logico abbinato, il numero assegnato va' in ordine crescente. Ad esempio, "1", "2", "3", eccetera, eccetera, da sinistra verso destra.
Quando si desidera far vocalizzare il risultato memorizzato di una o più di queste espressioni, basterà usare il numero logico abbinato preceduto dalla: "\", (barra diagonale rovesciata), ad esempio, nel campo voce in sostituzione scriveremo "\1","\2","\3", e così via; E' anche possibile inserire del testo fra di essi. Di esempi pratici, ce ne sono a iosa nei dizionari che è possibile scaricare dalla sezione download.
Prendiamo ad esempio la parola "papera". Sappiamo tutti che la parola "papera" può comprendere: "papere", "paperi", "papero", eccetera.
Un'altro screen reader grazie al suo asterisco ci risolverebbe il problema così: "paper*"e la parola verrebbe correttamente matchata con ogni sua lettera finale.
Però, se la parola è "paperino", o "paperella", oppure "paperone", eccetera, eccetera,non si avranno i risultati desiderati, ma si avranno solo errori di lettura e purtroppo senza la possibilità di metterci una toppa.
NVDA, invece, grazie a una sola Regex fa' questo e altro, in questo modo: "(PAPER|[pP]aper)([aAeEiIoO]\W)".
Tradotto in parole povere, con questa espressione diciamo a NVDA: se trovi la parola "PAPER" in maiuscolo, o in alternativa la stessa parola, ma in minuscolo, anche se l'iniziale è in maiuscolo, ti ho messo tra parentesi anche due cose che voglio, la prima è un elenco delle lettere accettabili e te le ho definite in una classe fra parentesi quadre, la seconda è che non vi sia dell'altro attaccato e te l'ho indicato con "\W"(barra diagonale rovesciata, doppiavu maiuscola), sono tra parentesi tonde perché voglio che ne memorizzi il risultato per me.
Nel campo della voce in sostituzione basterà fare così: "pàper\2", in pratica, si mette la parola corretta, in questo caso: "pàper" con la "a" accentata, mentre se ci si chiede cos'è quel: "\2", barra rovesciata due, la risposta è presto detta.
Quello è il nostro asterisco personalizzato, al modulo avevamo detto di memorizzare qualcosa, no? Questo sistema si usa quando non si sa esattamente di quale parola si tratterà, cioè lo si sa in parte. Infatti, noi non sappiamo se la parola matchata sarà tutta in maiuscolo, tutta in minuscolo, e con quale vocale terminerà. Ecco perché gli abbiamo detto di memorizzarselo.
La nostra vocale è stata memorizzata grazie all'uso delle parentesi tonde e, nel nostro caso, inserita nel secondo gruppo. Per mettere la giusta vocale affiancata alla nostra parola in sostituzione "pàper" abbiamo semplicemente detto di aggiungere ciò che gli è stato imposto di ricordare, (memorizzare), nel nostro caso ci interessava il risultato dell'espressione racchiusa fra parentesi tonde del secondo gruppo, partendo da sinistra, questo è il secondo. Ecco il significato di quel "\2", (barra diagonale rovesciata 2).
La "\W"(barra rovesciata doppiavu maiuscola) serve a impedire che la parola: "paper" abbia appiccicato qualcos'altro oltre a ciò che abbiamo indicato nella classe fra parentesi quadre. Questo carattere speciale "\W" accetta solo tutto ciò che non è una parola, a parte i caratteri di spaziatura e tabulazione. Nel nostro caso tutte le vocali in minuscolo o in maiuscolo sono ammesse, discriminando però la u o qualsiasi altro carattere, o parola, ma non la punteggiatura.
Se ad esempio la parola fosse stata "paperoga", "paperinik", o qualsiasi altra simile, l'ultimo carattere speciale che abbiamo appena visto renderebbe "false" (non vera) la condizione, quindi, verrebbe ignorata.
L'esempio precedente potrebbe funzionare anche così: "(PAPER|[pP]aper)(.\W)".
Stessa sintassi, ma al posto della classe fra parentesi quadre, inserita all'interno del secondo gruppo, abbiamo messo un semplice punto fermo.
Il punto fermo è un carattere speciale, equivalente all'asterisco usato ad esempio in Jaws. Esso infatti accetta un qualsiasi carattere.
Ecco un esempio: "zodiaca". Anche questo vocabolo può variare cambiando la vocale finale "zodiaci", "zodiaco", ma può anche essere "zodiache". E qui c'è un'acca di troppo; Mentre la parola: "zodiacale" o qualsiasi altra la vorremmo escludere, ecco unapossibile soluzione: "(ZODIAC|[zZ]odiac)(.{1,2}\W)".
Ormai conoscete la sintassi per far matchare parole maiuscole e minuscole con anche l'iniziale. E' sempre quella! La cosa che invece voglio farvi notare è racchiusa nel gruppo di parentesi tonde, il nostro asterisco personalizzato.
Ormai credo sia chiaro che racchiudere qualcosa fra parentesi tonde, vuol dire al nostro modulo dizionario di memorizzare ilcontenuto per rendercelo disponibile semplicemente richiamando il numero corrispondente del gruppo, precedendolo con il carattere speciale "\" (barra diagonale rovesciata); questa volta non ho usato un solo punto, ma grazie alle "{}", parentesi graffe, ho indicato un minimo e un massimo di caratteri ignoti, rappresentati dal ".", punto fermo, nel nostro caso, almeno uno e massimo due.
Nota: usare nel secondo parametro un valore inferiore al primo, non è ammesso. Se si omette il secondo parametro, lasciando la virgola, è come dire "illimitatamente". Mettere solo un parametro con valore maggiore di zero, vuol dire allo stesso tempo minimo e massimo. Mettere un solo parametro e con valore zero?, o negativo....?
Se volete divertirvi un pochino, ecco un giochino che potete provare afare tramite il dizionario temporaneo di NVDA.
Apritelo e aggiungete questa voce: "falso([aeiou]{2,4}\W)".
Mettete nel campo voce in sostituzione la seguente stringa: "vero, \1".
Come più volte detto, vi raccomando di non usare anche le virgolette!
aprite il Blocco note e scrivete: "falso".
Se avete fatto caso alla Regex appena immessa nel dizionario temporaneo, certamente avrete notato che cosa si deve aspettare da noi il modulo.
Per far sì che la condizione diventi "vera" occorre che si immetta uno qualsiasi dei caratteri elencati fra le parentesi quadre, ok?
Ma, un minimo di due, fino a un massimo di quattro, giusto?
Quindi è vero se digito almeno due qualsiasi, dei caratteri consentiti nella classe. Ma è altresì vero se ne digito in totale quattro, basta che siano quelli consentiti.
E' altresì vero se digito ogni singolo carattere da 2 a quattro volte, uno qualsiasi di quelli consentiti. Oppure almeno quattro dei caratteri consentiti, ma sempre un minimo di due.
Ora, provate invece a inserire un carattere non compreso nella classe consentita e vedrete che la condizione non sarà più vera, ma falsa e la sintesi ve lo dirà!
Provate anche a cambiare i valori dei parametri per vedere che succede, e vedrete che non è poi così difficile apprenderne il meccanismo.
Le parentesi graffe si possono ottenere facilmente premendo la combinazione "alt sinistro+123" dal tastierino numerico per la parentesi graffa aperta e "alt sinistro+125" per la parentesi graffa chiusa.
Il carattere che precede la parentesi graffa aperta subirà l'effetto conteggiato nelle parentesi graffe, nel nostro caso, il carattere speciale ".", punto fermo. Questo sarebbe valido anche se al posto del punto fermo ci fosse un qualsiasi carattere alfanumerico o una classe di caratteri racchiusa fra parentesi quadre. In pratica, verrebbero accettati un numero minimo ed un numero massimo di caratteri della classe definita come indicato dai due numeri nelle parentesi graffe separati da una virgola.
Ma torniamo all'esempio "zodiac". Ecco cosa metteremo nel campo della voce in sostituzione: "zodìac\2", la parola "zodìac" con la "i" accentata, seguita dal richiamo del risultato memorizzato nel secondo gruppo di parentesi tonde.
Anche qui il carattere speciale ci viene in aiuto limitando il matching solo a ciò che abbiamo impostato noi, cioè uno o 2 caratteri qualsiasi in più e nient'altro. Quindi verrà anche matchata: "zodiache", ma non qualsiasi altra parola più lunga. Ovviamente "zodiacale", "zodiacali", eccetera verranno escluse e non subiranno alterazioni di sorta. Ciò non impedirà però di matchare: "zodiac" seguita da un massimo di caratteri da noi definiti nella Regex d'esempio anche se in un ordine invertito, ad esempio con l'acca alla fine.
Altrimenti, occorre usare una serie di alternative, che indichi quali caratteri accettare, e potrebbe essere così: "(ZODIAC|[zZ]odiac)(HE|he|[aAiIoO])(\W)".
In questo caso abbiamo aggiunto: "HE|he", per dire che è consentita la parola: "zodiac" seguita da: "HE" in maiuscolo o "he" in minuscolo, in aggiunta anche una lista di vocali minuscole e maiuscole consentite che abbiamo racchiuso nella classe fra parentesi quadre. avrete notato, infatti, che ho usato un operatore "|" (or) per definire due alternative, contenenti rispettivamente il frammento di parola "HE", e "he", in maiuscolo e in minuscolo. Ecco perché le ho dovute raggruppare fra parentesi tonde nel secondo gruppo. Il terzo e ultimo gruppo contiene il carattere speciale "barra diagonale rovesciata doppia vu maiuscola", che assicura la chiusura della parola a ulteriori caratteri.
Quindi, le parentesi tonde sono molto utili anche per raggruppare qualcosa come del testo, che verrà interpretato nell'ordine da noi digitato, a differenza di una classe che indica un carattere fra i caratteri.
La voce da mettere nel campo in sostituzione, in questo esempio, sarà: "zodìac\2\3".
Il nostro asterisco virtuale lo si può usare anche a sinistra del vocabolo, cosa che, vi assicuro, Jaws non fa, a dimostrazione della potenzialità delle Regex.
Vediamo un po', per esempio, alcune sintesi vocali non leggono bene un nome straniero tipo: "Ross", o "Gibb"; nella maggior parte dei casi viene letta sillabata.
In lingua italiana, però, la parola: "Ros" può essere contenuta in: "Rosso", "Rossiccio", "Rossano", eccetera eccetera,e la parola: "Gibb" può essere contenuta in: "Gibbone", giusto?
Allora come facciamo a escludere dal matching quelle parole e specificare che la correzione deve essere fatta solo al nome: "Ross", o "Gibb"?
Un modo è questo: "(\W|^)(ROSS|[rR]oss)(\W)".
il primo gruppo di parentesi tonde, che precede il vero vocabolo da matchare serve ad indicare che a sinistra di questi non vi sia nulla a parte spaziature, o punteggiatura, nessun carattere alfanumerico; lo si può anche sostituire, nella maggior parte dei casi, anche con: "(\b)", (barra diagonale rovesciata b).
Ricordatelo, perché: "(\W|^)"o "(\b)", vi verrànno in soccorso in quei casi di conflittualità di alcune parole,come ad esempio: "girasole"; se nel vostro dizionario aveste in precedenza aggiunto un vocabolo come questo: "asole". La parola, infatti, è contenuta in: "girasole", potrebbe verificarsi appunto il caso di conflittualità che vi dicevo, e avrebbe priorità la parola più a monte, sì, perché i vocaboli vengono memorizzati nell'ordine da noi imposto, e in cascata, ecco perché ritengo necessario cercare di mantenere nel nostro dizionario un ordine alfabetico il più approssimato possibile, ciò ci aiuterà non poco nel "de-bug", (snidare dei conflitti, e vi garantisco che con le Regex succede!
Quindi, quando si inserisce un nuovo vocabolo e sembra non avere effetto, occorre armarsi di un po' di pazienza e usando magari il "blocco note" cercare la parola che genera il conflitto, e una volta trovata, anteponendole poi: "(W|^)",o "(\b)", in modo da indicare che deve essere una parola a se, e non nidificata in un'altra, fare poi la modifica del caso anche alla voce in sostituzione che si trova dopo la tabulazione, se essa dovesse contenere dei richiami a dei gruppi di espressioni, occorrerà ovviamente aggiornarli perché ne abbiamo aggiunta una nuova e i numeri logici di riferimento non hanno più ragione di essere, ad esempio la riga: "(ASOL|[aA]sol)(.\W)", e in sostituzione: "àsol\2".
Se la andassimo a modificare aggiungendo l'espressioncina che avevo descritto, la riga diventerebbe così: "(\W|^)(ASOL|[aA]sol)(.\W)", e in sostituzione: "\1àsol\3".
Torniamo a noi, come vedete la nostra "\W", (barra diagonale rovesciata doppiavu maiuscola) ci viene in aiuto anche se messa a sinistra.
Subito dopo abbiamo posto un'alternativa tramite il consueto carattere speciale "|"(or), seguito dall'accento circonflesso, l'apice in questo caso indica che il matching è valido anche se il vocabolo è a inizio linea.
Quindi, abbiamo già scartato che la parola si trovi inserita ad esempio in: "grosso", "infrarossi", "prossimo", eccetera eccetera.
Alla destra del vocabolo invece ancora il nostro carattere magico "\W" (barra diagonale rovesciata doppiavu maiuscola) racchiuso fra parentesi tonde, che si occupa della chiusura della regex.
In totale abbiamo tre gruppi racchiusi fra parentesi tonde, a noi servono il primo ed il terzo; in essi, sono memorizzati i caratteri separatori che ci servono. Allora, la nostra voce in sostituzione potrebbe essere: "\1ros\3".
Provate a verificare e vedrete che: "rosso", "grosso", infrarosso", eccetera non subiranno alterazioni.
Ma non abbiamo ancora finito! Infatti, è anche possibile creare il nostro asterisco virtuale nel bel mezzo di un vocabolo; Poniamo il caso di voler matchare una parola che al suo interno abbia uno spazio, come ad esempio, "juke box", e, ovviamente, vorremmo applicare le nostre solite regole di maiuscolo/minuscolo, eccetera, eccetera, che ormai abbiamo consolidato. Ecco come è possibile farlo: "(JUKE|[jJ]uke)(\W|)(BOX|[bB]ox)".
Se fra le due parole c'è uno spazio o un carattere di separazione come il trattino o il sottolineato, o addirittura niente, cioè le due parole sono attaccate, il matching sarà "true", cioè vero ugualmente.
In parole povere, con il nostro asterisco personalizzato che abbiamo posto nel secondo gruppo al centro delle due parole, abbiamo detto che è ammesso un solo carattere separatore come: (spazio, il trattino, o il sottolineato o la tabulazione, badate bene, uno solo di essi). Infine, notate la barra verticale, (l'operatore or) solo soletto con niente alla sua destra, appunto, vuol proprio dire letteralmente "oppure niente", e questo permette di matchare le due parole anche se appiccicate.
Faccio notare che se però si volesse fare accettare più di un solo carattere (in questo caso, un separatore), come nell'esempio citato è sempre possibile ricorrere al trucchetto delle parentesi graffe che abbiamo visto in precedenza; Ripeto, esse ci consentono di definire il numero di ripetizioni consentite del carattere che le precede, quindi, se si volesse porre un limite massimo, ad esempio di due caratteri, si potrebbe fare una piccola modifica alla nostra Regex, ovviamente nel gruppo ove risiede il nostro asterisco centrale virtuale personalizzato, così: "(JUKE|[jJ]uke)(\W{2}|)(BOX|[bB]ox)".
Oppure, per una ripetizione illimitata si può usare il simbolo "+", così: "(JUKE|[jJ]uke)(\W+|)(BOX|[bB]ox)"; Il carattere "+" ecquivale a "{1,}".
Il simbolo "+", indica che è ammessa almeno una ripetizione del carattere che lo precede, e non pone limiti nelle ripetizioni.
In questo esempio abbiamo aggiunto la"|" (barra verticale, or), per indicare che è ammesso anche niente fra le due parole.
Un altro simbolo speciale, che semplifica tutto è "*", l'asterisco, a differenza del "+", consente un numero illimitato di ripetizioni del carattere che lo precede, ma anche nessuna; ecquivale a "(\W+|)".
Così la nostra regex potrebbe essere modificata così "(JUKE|[jJ]uke)(\W*)(BOX|[bB]ox)".
Una assurdità insomma, ad ogni modo l'incantesimo avrebbe fine nonappena la seconda parola dovesse andare a capo in una nuova linea). Ah!Dimenticavo... la parola da mettere nel campo in sostituzione in questo caso è: "giubox" e senza tanti fronzoli.
Se invece la "w", è usata in minuscolo, il carattere speciale: "\w", (barra diagonale rovesciata doppia vu) ci permette ovviamente tutto l'opposto.
Essa infatti permette di matchare del testo appiccicato o inserito in una riga di altro testo, ad esempio, volendo matchare il punto fermo presente fra due parole come: "Tizio@provider.com", si potrebbe fare così: "(\w)\.(\w)".
Come voce in sostituzione mettere: "\1 punto \2".
In parole povere abbiamo detto, se in una riga di testo, nel bel mezzo di questa, trovi il carattere "punto", (notate che il punto è preceduto dalla "\"barra diagonale rovesciata proprio per rendere il ".", punto fermo, che normalmente è di per sè un carattere speciale, questa volta è un normale carattere con il suo significato letterale), e voglio che subito dopo del punto vi sia attaccato altro testo.
Se si omettesse la seconda espressione verrebbero anche letti tutti i punti di a capo e di fine paragrafo.
Come avete visto le combinazioni sono infinite e tutto dipende dalla nostra fantasia, e se si rispettano le sintassi si possono ottenere molti risultati soddisfacenti, e non abbiamo ancora visto tutto!
Segue con la terza parte...

Adriano Barbieri.