Nel post precedente abbiamo visto come trovare correttamente le differenze fra le righe di due testi, ma quali applicazione ha?
Innanzitutto premettiamo che il metodo visto si può applicare alle righe di un testo, come alle parole, alle lettere, ai puntini che compongono un'immagine, a qualsiasi cosa.
I siti come
Dropbox,
Google,
Mega, offrono di ospitare i vostri file e, ogni volta che aggiornate un file, di mantenere le versioni precedenti. Per risparmiare spazio, invece di avere più copie di file con piccole differenza, mantengono nei loro archivi solo un file e le successive differenze.
Anche nei formati video digitali, ogni 5 fotogrammi, abbiamo i dati di un fotogramma intero e solo le differenze per i successivi 4 fotogrammi; sempre per ridurre spazio.
Trovare le differenza ci serve anche in biologia e medicina, per capire cosa è effettivamente cambiato in un DNA, da una specie ad un'altra, o una lunga molecola organica come si è modificata.
Nel campo dell'informatica, si possono mandare solo i DIFF di un programma, e i programmi di
patch, applicheranno solo le modifiche; in questo modo non c'è bisogno di inviare tutto il programma.
Ora vediamo di creare un programma che ci faccia vedere le differenze fra sue testi, molto usato in informatica.
Ci basterà sfruttare il codice mostrato nell'altro post, aggiungendo il solo il modo di colorare il testo.
Otterremo un programma simile a questo:
Nelle due colonne in basso a destra abbiamo i due testi affiancati con le righe eliminate in rosso e quelle aggiunte in verde. Chiamando questi due campi rispettivamente: VersAdiff e VersBdiff, il codice per ottenere il testo colorato è il seguente:
on mouseUp
#trasformiamo i testi in array, dove ogni riga è un elemento dell'array
put the text field "versA" into tOldSource
put the text field "versB" into tNewSource
split tOldSource using return
split tNewSource using return
#cerchiamo di capire di quanti elementi, cioè righe, è fatto ogni array
#extents mostra una serie di righe con due numeri, il numero minimo e il massimo per ogni dimensione dell'array
#qui la dimensione è 1
put item 2 of the extents of tOldSource into tOldLineCount
put item 2 of the extents of tNewSource into tNewLineCount
#calcoliamo le varie sequenze con il massimo testo in comune (LCSL)
put CalculateLCSLengths(tOldSource, tNewSource, tOldLineCount, tNewLineCount) into LCLS
#e adesso calcoliamo il DIFF
lock screen
put empty into field "VersAdiff"
put empty into field "VersBdiff"
DetermineDiff LCLS, tOldSource, tNewSource, tOldLineCount, tNewLineCount
DetermineDiff2 LCLS, tOldSource, tNewSource, tOldLineCount, tNewLineCount
unlock screen
end mouseUp
function CalculateLCSLengths tOldSource, tNewSource, tOldLineCount, tNewLineCount
#costruiamo la tabella per il calcolo LCSL
#la riga 0 è tutti 0
repeat with tRow = 0 to tOldLineCount
put 0 into pLCSLength[tRow,0]
end repeat
#la colonna 0 è tutti 0
repeat with tCol = 0 to tNewLineCount
put 0 into pLCSLength[0,tCol]
end repeat
#ora calcoliamo le altre varie celle della matrice LCLS
repeat with tRow = 1 to tOldLineCount
repeat with tCol = 1 to tNewLineCount
put tOldSource[tRow] into tOldLine
put tNewSource[tCol] into tNewLine
if tOldLine = tNewLine then
put pLCSLength[tRow - 1,tCol - 1] + 1 into pLCSLength[tRow,tCol]
else
put max(pLCSLength[tRow - 1,tCol],pLCSLength[tRow,tCol - 1]) into pLCSLength[tRow,tCol]
end if
end repeat
end repeat
#finito
return pLCSLength
end CalculateLCSLengths
#abbiamo un messaggio che chiama se stesso parecchie volte
#qui usiamo le @ per risparmiare meomoria ed evitare troppe copie della stessa variabile, però stiamo attenti a non modificarle!
on DetermineDiff @pLCSLength, @pOldSource, @pNewSource, pRow, pCol
put pOldSource[pRow] into tOldLine #la riga nel file originale
put pNewSource[pCol] into tNewLine #la riga nella nuova versione
if pRow > 0 and pCol > 0 and tOldLine = tNewLine then
#sono uguali, andiamo alla cella in alto a sinistra rispetto all'attuale nel LCLS
DetermineDiff pLCSLength, pOldSource, pNewSource, pRow - 1, pCol - 1
put the htmltext of field versAdiff into temp
set the htmltext of field VersAdiff to ( temp & prow & "	" & tOldLine )
else if pCol > 0 and (pRow = 0 or pLCSLength[pRow,pCol - 1] >= pLCSLength[pRow - 1, pCol]) then
##caso la cella a sinistra è maggiore o uguale di quella sopra
#è stata aggiunta una riga, moviamoci a sinistra nella tabella LCLS
DetermineDiff pLCSLength, pOldSource, pNewSource, pRow, pCol - 1
#set the text of field uscita to (field uscita & prow& "+" & tab & tNewLine & return )
else if pRow > 0 and (pCol = 0 or pLCSLength[pRow,pCol - 1] < pLCSLength[pRow - 1, pCol]) then
##caso la cella a sinistra è minore di quella sopra
#è stata rimossa una riga, saliamo di una riga nella tabella LCLS
DetermineDiff pLCSLength, pOldSource, pNewSource, pRow - 1, pCol
put the htmltext of field VersAdiff into temp
set the htmltext of field VersAdiff to (temp &"<font bgcolor=red>" & prow & "	" & tOldLine & "</font>" )
end if
end DetermineDiff
#abbiamo un messaggio che chiama se stesso parecchie volte
#qui usiamo le @ per risparmiare meomoria ed evitare troppe copie della stessa variabile, però stiamo attenti a non modificarle!
on DetermineDiff2 @pLCSLength, @pOldSource, @pNewSource, pRow, pCol
put pOldSource[pRow] into tOldLine #la riga nel file originale
put pNewSource[pCol] into tNewLine #la riga nella nuova versione
if pRow > 0 and pCol > 0 and tOldLine = tNewLine then
#sono uguali, andiamo alla cella in alto a sinistra rispetto all'attuale nel LCLS
DetermineDiff2 pLCSLength, pOldSource, pNewSource, pRow - 1, pCol - 1
put the htmltext of field versBdiff into temp
set the htmltext of field VersBdiff to ( temp & prow & "	" & tOldLine )
else if pCol > 0 and (pRow = 0 or pLCSLength[pRow,pCol - 1] >= pLCSLength[pRow - 1, pCol]) then
##caso la cella a sinistra è maggiore o uguale di quella sopra
#è stata aggiunta una riga, moviamoci a sinistra nella tabella LCLS
DetermineDiff2 pLCSLength, pOldSource, pNewSource, pRow, pCol - 1
put the htmltext of field VersBdiff into temp
set the htmltext of field VersBdiff to (temp & "<font bgcolor=green>" & prow & "	" & tNewLine & "</font>")
else if pRow > 0 and (pCol = 0 or pLCSLength[pRow,pCol - 1] < pLCSLength[pRow - 1, pCol]) then
##caso la cella a sinistra è minore di quella sopra
#è stata rimossa una riga, saliamo di una riga nella tabella LCLS
DetermineDiff2 pLCSLength, pOldSource, pNewSource, pRow - 1, pCol
end if
end DetermineDiff2
Possiamo renderlo graficamente più professionale facendo in modo che muovendo un solo scroller, tutte i due testi scorrano contemporaneamente, mostrando sempre proporzionalmente la stesse parti. Ci basterà levare lo scroll verticale dal campo VersAdiff, e mettere nel secondo campo (VersBdiff) il seguente codice:
on scrollbardrag tdrag
put the formattedheight of me into myh
put the formattedheight of field versAdiff into ah
put tdrag / myh into perc
put round(perc * ah) into ah2
set the vscroll of field "VersADiff" to ah2
end scrollbardrag
arrivati a questo punto, affiancandoli bene avremo il risultato voluto.
Come vedete si riesce a vedere bene cosa è stato aggiunto e cosa è stato levato.
Il programma è scaricabile da qui:
diff.livecode
Questo tipo di analisi, tipica dell'informatica, è applicabile a qualunque campo. Voi dove l'applichereste?