none
vb.net - Verificare differenze tra due richtextbox e riportarne le differenze nella terza RRS feed

  • Domanda

  • Salve a tutti, 

    premetto di aver già chiesto nel forum inglese, non è mia intenzione fare cross posting, ma la maniera in cui sono stato risposto non coincide davvero con il rispetto che vige davvero sui forum MSDN.

    La mia richiesta di aiuto consiste nello filtrare quello che c'è nella rtb1 rispetto alla rtb2.

    Esempio.

    rtb1 = ciao mi chiamo Mattia

               sono un ragazzo italiano

    rtb2= ciao chiamo Mattia 95 

               sono un ragazzo sardo

    rtb3 dovrebbe fare : rtb1-rtb2= mi 95
                                                   sardo

    Ho già perlustrato a lungo nel web, ma trovo solo codici  poco funzionanti o obsoleti con cui non sono riuscito a risolvere.

    Molti di questi richiedono la selezione delle differenze, ma nel mio caso, mi interessa soltanto la differenza tra rtb1 e rtb2.

    rtb1 viene aggiornata da una pagina web

    rtb2 contiene il vecchio aggiornamento della pagina web

    dunque rtb3 mi dice quali differenze ci sono tra il nuovo aggiornamento(rtb1) e il vecchio (rtb2)

    Spero di essere stato chiaro e sono pronto per dare qualsiasi altro chiarimento.

    Cordiali Saluti

    Mattia 

    giovedì 18 giugno 2020 14:16

Risposte

  • Solo per completezza... se la necessità è di utilizzare uno strumento che gestisca le differenze tra due file mi permetto, nel caso non lo si conosca già, di segnalare il mitico WinMerge, un'applicazione gratuita che mi ha salvato innumerevoli volte. 

    • Contrassegnato come risposta Mattia Fanti lunedì 29 giugno 2020 18:21
    sabato 20 giugno 2020 15:27

Tutte le risposte

  • Se preferisci usare linq:

    Dim rtb1 = "ciao mi chiamo Mattia sono un ragazzo italiano"
    Dim rtb2 = "ciao chiamo Mattia 95 sono un ragazzo sardo"
    Dim split = " "
    Dim rtb3 = String.Join(split, string.Format("{0} {1}",rtb1,rtb2).Split(split).GroupBy(Function(g) g).Where(Function(w) w.Count() < 2).[Select](Function(s) s.Key))
    		

    In questo caso accodi le due stringhe e dividi le parole tramite lo spazio, dopo le raggruppi e filtri tutti quei gruppi che contano una sola parola, in fine ricongiungi la stringa con l'elenco delle parole risultanti.

    giovedì 18 giugno 2020 18:32
  • Ciao U235,

    grazie per la tua risposta. ILa soluzione proposta su stackoverflow non mi soddisfaceva in quanto non è mia intenzione tenere i dati vecchi, ma solo le parole nuove che non vengono usate nel vecchio update.

    Ho provato il tuo codice e come output ottengo:

    mi italiano 95 sardo


    In effetti mi sono spiegato male io dall'inizio.

    supponendo

    Dim rtb1 = "ciao mi chiamo Mattia sono un ragazzo italiano"
    Dim rtb2 = "ciao chiamo Mattia 95 sono un ragazzo sardo"


    rtb1 è aggiornata constantemente, mentre rtb2 contiene il vecchio update del testo.

    Quello che vorrei fare, è verificare  e riportare in rtb3 ogni minimo cambiamento del testo.

    Dunque il reale output che mi interessa sarebbe:

    mi italiano


    Ora, ho provato il tuo codice per fare una cosa del genere, in quanto ho dei testi lunghi da comparare.

     Dim rtb1 = Richtextbox1.Text
            Dim rtb2 = richtextbox2.Text
            Dim split = " "
            Dim rtb3 = String.Join(split, String.Format("{0} {1}", rtb1, rtb2).Split(split).GroupBy(Function(g) g).Where(Function(w) w.Count() < 2).[Select](Function(s) s.Key))
    
    richtextbox3.text= rtb.tostring

    ma non mi da nessun risultato purtroppo.

    Grazie

    Mattia 

    giovedì 18 giugno 2020 21:25
  • Ciao Mattia,

    di modi ce ne sono diversi, ma di per se non è difficile ottenere un risultato, poi si può valutare cosa sia meglio come facilità di lettura o velocità di esecuzione, diciamo cosa sia più ottimizzato nel tuo caso.

    Un altro esempio (dopo il tuo aggiornamento) potrebbe essere questo:

        Dim rtb1 = "ciao mi chiamo Mattia sono un ragazzo italiano"
        Dim rtb2 = "ciao chiamo Mattia 95 sono un ragazzo sardo"
        Dim split = " "
        Dim oldList = rtb2.Split(split)
        Dim rtb3 = String.Join(split, rtb1.Split(split).Where(Function(w) Not oldList.Contains(w)))

    EDIT:

    Dim rtb1 = "ciao mi chiamo Mattia sono un ragazzo italiano"
    Dim rtb2 = "ciao chiamo Mattia 95 sono un ragazzo sardo"
    Dim split = " "
    Dim rtb3 = String.Join(split, rtb1.Split(split).Except(rtb2.Split(split)))


    • Modificato U 235 giovedì 18 giugno 2020 22:26
    giovedì 18 giugno 2020 22:06
  • Ciao U235, 

    grazie mille! Il codice sembra funzionare, però, ho subito notato che, confrontando le due textbox, i testi devono essere nella stessa linea per essere confrontati.

    Allego uno screenshot che spiega meglio.

    Ci sarebbe la possibilità di filtrare completamente le parole differenti tra rtb1 e rtb2 a prescindere dalla loro posizione?

    Grazie

    Mattia

    venerdì 19 giugno 2020 00:19
  • Devi prima sostituire i ritorni accapo delle 2 rtb con " "
    venerdì 19 giugno 2020 05:29
  • @Mattia

    Buongiorno, sta diventando un po più complesso risponderti, questo perché hai già cambiato 3 volte la singola richiesta, e senza capirne bene le tue finalità la domanda dovrebbe avere una risposta fine a se stessa e non seguire i vari problemi successivi. Diversamente spiega meglio le finalità, cosa vuoi fare esattamente? Ti potrei rispondere che se devi confrontare riga per riga allora devi dividere la stringa tramite il carattere "nuova linea" e poi confrontare come sopra dividendo la riga in parole (o la riga in frasi e a loro volta in parole ecc.) e confrontarla con la corrispondente della seconda stringa. Ma c'è da dire che comunque il confronto non sarà preciso perché nella stessa riga (o comunque nel testo confrontato comunque lo suddivida) può esserci una parola che nel testo può essere "nuova" in una nuova posizione, mentre successivamente no o viceversa. Ad esempio: "Ciao mi chiamo Mattia ma per tutti sono Mat." e "Ciao sono Mattia ma tutti mi chiamano Mat." produrrebbe "chiamo" e "per", ma se aggiungo una parte: "Ciao mi chiamo Mattia ma per tutti sono Mat. Ti chiamo per prova" e "Ciao sono Mattia ma tutti mi chiamano Mat. Ti chiamo per prova", ecco che non ottengo nessun risultato perché "chiamo" e "per" sono già presenti nella frase (Ti chiamo per prova), per cui non vengono più conteggiati, il che se vogliamo potrebbe essere sia corretto che no. In una logica "booleana" in cui o è ESATTAMENTE uguale oppure è diverso, il risultato ottenuto sarebbe scorretto (comunque sempre incline all'errore a causa della sua rigidità), ma in realtà la frase è la stessa (quindi corretto, nessuna differenza) vista in una logica più "umana" incline all'interpretazione. Ma questo purtroppo è solo un esempio, potresti avere problemi con le righe sfalsate ecc. quindi dovrai essere ben preparato e parecchio autonomo... A che ti serve avere "chiamo" e "per"? Informaticamente parlando che ne fai?

    • Modificato U 235 venerdì 19 giugno 2020 05:50
    venerdì 19 giugno 2020 05:30
  • Devi prima sostituire i ritorni accapo delle 2 rtb con " "

    Giusto. Nel caso un problema potrebbe essere che il carattere "speciale" (vale anche per tab ecc.) sia attaccato ad una parola tipo quando si va a capo senza mettere uno spazio prima, il risultato sarà una parola diversa in quanto vengono giunte due parole (ultima parola riga + carattere newline + prima parola nuova riga).

    Io consiglierei fare un replace dei caratteri speciali mettendoli uno spazio davanti e dietro, dopo usare lo split con l'opzione StringSplitOptions.None in modo che mi crei item anche per anche li spazi vuoti (vedi davanti a " sono italiano") e dopo fare una where includendo anche la formattazione.

    Dim rtb1 = string.Format("ciao{0}mi chiamo Mattia{0} sono un ragazzo{0} italiano",Environment.NewLine).Replace(Environment.NewLine, string.Format(" {0} ",Environment.NewLine))
    Dim rtb2 = string.Format("ciao{0}chiamo Mattia 95{0} sono un ragazzo{0} sardo",Environment.NewLine).Replace(Environment.NewLine, string.Format(" {0} ",Environment.NewLine))
    Dim split = {" "c}
    Dim oldList = rtb2.Split(split).Distinct()
    Dim rtb3 = String.Join(" ", rtb1.Split(split, StringSplitOptions.None).Where(Function(w) String.IsNullOrWhiteSpace(w) OrElse w.Equals(Environment.NewLine) OrElse Not oldList.Contains(w)))
    esempio 


    • Modificato U 235 venerdì 19 giugno 2020 05:56
    venerdì 19 giugno 2020 05:47
  • Ciao U 235  e patel45.

    Il tuo codice proposto funziona alla perfeziona solo e soltanto se confronto due linee nella stessa posizione.

    Appena inizio a splittare random le parole in diverse linee allora inizia a non filtrare più le nuove parole. 

    Mi scuso ancora per non aver spiegato bene il problema nei minimi dettagli fin dall'inizio e questo mi ha fatto dilagare un pò.

    Quello che sto cercando di ottenere sarebbe un eliminare ogni parola presente in rtb1 da rtb2.

    A prescindere dalla posizione. Non sono interessato a comparare le linee. Infatti, se rtb1 contiene:

    ciao mi 
    chiamo
    Mattia
    e sono 
    un ragazzo italiano


    ed rtb2 contiene:

    e sono un ragazzo sardo
    Mattia 
    ciao chiamo


    rtb3 dovrebbe contenere solo

    mi italiano

    Senza badare alla loro posizione. Una sorta di "cerca tutte le parole presenti in rtb1 ed eliminale da rtb2 a prescindere dalla loro posizione e/o spazi a capo etc. e mostrale su rtb3 .

    Spero sia stato più chiaro.

    Grazie, 

    Mattia

    venerdì 19 giugno 2020 09:27
  • Ciao U 235  e patel45.

    Il tuo codice proposto funziona alla perfeziona solo e soltanto se confronto due linee nella stessa posizione.

    Appena inizio a splittare random le parole in diverse linee allora inizia a non filtrare più le nuove parole. 

    Mi scuso ancora per non aver spiegato bene il problema nei minimi dettagli fin dall'inizio e questo mi ha fatto dilagare un pò.

    Quello che sto cercando di ottenere sarebbe un eliminare ogni parola presente in rtb1 da rtb2.

    A prescindere dalla posizione. Non sono interessato a comparare le linee. Infatti, se rtb1 contiene:

    ciao mi 
    chiamo
    Mattia
    e sono 
    un ragazzo italiano


    ed rtb2 contiene:

    e sono un ragazzo sardo
    Mattia 
    ciao chiamo


    rtb3 dovrebbe contenere solo

    mi italiano

    Senza badare alla loro posizione. Una sorta di "cerca tutte le parole presenti in rtb1 ed eliminale da rtb2 a prescindere dalla loro posizione e/o spazi a capo etc. e mostrale su rtb3 .

    Spero sia stato più chiaro.

    Grazie, 

    Mattia

    Come spiegato nel post precedente non è un lavoro semplice. Se si tratta di un testo praticamente preimpostato e breve, le probabilità che trovi dei problemi sono poche, man mano che cresce è probabile che si verifichi quello che ti ho già spiegato nel post precedente, ovvero che se il testo che contiene le parole già presenti è relativamente grande, è molto alta la probabilità che la parola "nuova" nel primo testo sia presente in un altro punto del testo, decretandola di fatto come "già presente" nel vecchio testo, per cui non viene visto come cambiamento (ti ho fatto l'esempio dei due testi nel post precedente) non ottenendo risultati.

    Riporto qui i testi di esempio di prima:

    nuova=>"Ciao mi chiamo Mattia ma per tutti sono Mat. Ti chiamo per prova"

    vecchia=>"Ciao sono Mattia ma tutti mi chiamano Mat. Ti chiamo per prova"

    tra queste due frasi non vi sono parole che sono presenti nella nuova e non sono presenti nella vecchia, anche se le frasi sono diverse. Questo perché la parte dopo il punto (".") è letta in un unico blocco quindi con tutte le parole per diversi pezzi di frasi. Ma se applico una logica per suddividere (in questo esempio) in due blocchi distinti e contrapponibili allora il discorso cambia, se divido al punto (".") ed analizzo separatamente in due blocchi, ecco che ottengo "chiamo" e "per" nel primo pezzo di ogni blocco (prima del punto). Questo significa che dovrai applicare dei criteri che diventano veramente complessi da gestire perché non conosci a priori la struttura del testo, ecco perché dovresti iniziare a considerare di interpretare il testo. Una cosa tipo: "ciao"=[saluto]; "mi chiamo Mattia"= [presentazione]; "sono Mattia"= [presentazione]; e dopo confronti con: "i due saluti sono diversi?"=>no; "le due presentazioni sono diverse?"=>si nelle parole "mi" e "chiamo" ecc.) e non basarti solo su una logica del mero confronto tra stringhe, ma è fondamentale che tu sappia suddividere il testo in blocchi piccoli confrontabili per logica.

    ***************OT (apro e chiudo la questione, nessuna polemica e non insisto...)**********

    Quindi sapere a che ti serve recuperare le parole filtrate e per cosa le dovrai usare e come intendi farlo, direi che è fondamentale se vuoi essere aiutato in questo tuo progetto. Diversamente non possiamo occupare il forum con un post per ogni problema incontrato. Finiremmo per scrivere un romanzo che poi sarebbe inutile alla comunità.

    ******************************************************************************

    In ogni caso è FONDAMENTALE che tu abbia dimestichezza con le stringhe e i metodi di utilizzo di esse, di Linq (se lo vuoi usare) e/o cicli e condizioni ecc. che devono essere il tuo pane quotidiano, ma sopratutto devi allenarti un po ad ingegnarti a trovare soluzioni con li strumenti di cui disponi e che vuoi usare, quindi è fondamentale conoscere bene le basi.

    EDIT:

    Questa situazione mi ricorda quando, molto più inesperto di ora, provai a fare un riconoscimento di oggetti dentro un immagine, e pretendevo di farlo confrontando pixel per pixel senza guardare l'insieme... Come posso riconoscere una parte di un immagine guardando un solo puntino? impossibile... a meno che la parte da confrontare non è anch'esso un puntino.

    • Modificato U 235 venerdì 19 giugno 2020 12:29
    venerdì 19 giugno 2020 12:17
  • Ciao U235,

    ti ringrazio davvero per la tua risposta.

    Hai perfettamente ragione e , spiegare perchè mi serve filtrare questo senza dare una spiegazione generale, è abbastanza controproducente. 

    Ho un file di testo 

    pagina esempio

    questo verrà aggiornato, dunque vorrei sapere come è stato aggiornato. La mia idea era di filtrare tutto quello presente nell'aggiornamento vecchio e di conseguenza mostrare solo il nuovo, quello che cambia. Ora capisco che la situazione è un pò più difficile di quello che pensavo, tra questione di punto e spazi.


    Grazie,

    Mattia

    venerdì 19 giugno 2020 13:06
  • Spero di non essere stato scortese. Se ad esempio mi dici che è un programma che serve a te o ad uno sviluppatore durante lo sviluppo, di potrei rispondere che visto che non va in produzione potresti sfruttare visual studio per fare il merge di due file di testo (o copia incolla manuale oppure usi da codice la consolle e lanci devenv.exe /diff file1.txt file2.txt o qualcosa del genere nel caso cerca su google), il che comporta tu abbia visualstudio a disposizione. Visual studio che il cliente finale difficilmente avrebbe. Oppure potresti usare Powershell, se non sbaglio c’era qualche strumento. Se va bene potresti provare per vedere se ti è sufficiente e magari risparmiarti un po’ di lavoro. Non era per farmi i fatti tuoi ma per evitare di farti proposte a caso. Comunque non scoraggiarti, magari c’è qualcosa di molto più semplice da fare/usare e qualcuno lo posterà. Così se mai un giorno avessi bisogno di questa cosa saprei già come fare Anche io.
    venerdì 19 giugno 2020 14:25
  • Ciao, avete pensato alla possibilità di utilizzare delle librerie che diano già questa funzionalità?
    Googlando un po' ho visto la libreria DiffPlex su NuGet, e la documentazione su GitHub.

    Ma potrebbero essercene molte altre, non ci ho dedicato molto tempo.

    venerdì 19 giugno 2020 14:46
  • Ciao, avete pensato alla possibilità di utilizzare delle librerie che diano già questa funzionalità?
    Googlando un po' ho visto la libreria DiffPlex su NuGet, e la documentazione su GitHub.

    Ma potrebbero essercene molte altre, non ci ho dedicato molto tempo.

    Ciao,

    concordo. Credo che si possa spaziare da un buon sano utilizzo di una libreria già pronta, fino a provare a fare tutto a mano implementando algoritmi noti o addirittura provare a migliorare ciò che altri hanno già implementato egregiamente, dipende tutto dalle esigenze. Comunque a meno che non si tratti dell'ultimo caso (molto "accademico" ma certamente una potenziale perdita di tempo nella maggior parte dei casi) non vedo un buon motivo per riscriverlo da zero.

    venerdì 19 giugno 2020 15:11
  • Ciao,

    capisco la difficoltà dell'argomento, per cui ho deciso di limitarmi all'uso del tuo codice.

    Ho comunque un'idea alternativa. 

    Nel sito https://textuploader.com/ ti permette di verifiicare le revisioni del tuo codice, e per ciascuna, indica con delle linee rosse sbarrate quello che è stato eliminato, e scritte in verde, le nuove parole. Ecco, penso di agganciarmi a questo ora, al momento è quello che mi permette di verificare ciò che voglio verificare.

    Grazie mille

    Mattia

    sabato 20 giugno 2020 15:05
  • Solo per completezza... se la necessità è di utilizzare uno strumento che gestisca le differenze tra due file mi permetto, nel caso non lo si conosca già, di segnalare il mitico WinMerge, un'applicazione gratuita che mi ha salvato innumerevoli volte. 

    • Contrassegnato come risposta Mattia Fanti lunedì 29 giugno 2020 18:21
    sabato 20 giugno 2020 15:27