Come estrarre le parole da una frase e contare le eventuali parole ripetute
Ultima modifica: 21-06-2016

Domanda

Ho bisogno di poter estrarre da una frase inserita in una cella, l'elenco di tutte le parole contenute con a fianco scritto il numero di volte che ogni parola è ripetuta, e magari in ordine decrescente.

Faccio un esempio che forse è più facile farmi capire:

"non ci si mangia tra un cane ed un altro cane"

Dovrei ottenere qualcosa del genere:

un 2
cane 2
si 1
mangia 1
tra 1
non 1
ci 1
ed 1
altro 1

 

Risposta

Io risolverei la questione col metodo dei dati univoci già presentato tra queste pagine.

Per raggiungere lo scopo io seguirei questi passi:

leggo la frase dalla cella

la divido usando la funzione Split col carattere separatore spazio (" ") (questa operazione mi mette tutte le parole in una matrice)

inizio la raccolta dei dati univoci usando una Collection (come visto nel già citato articolo)

durante la raccolta dei dati univoci controllo lo stato dell'errore

se l'errore è diverso da 0 (zero) incremento il contatore (se c'è un errore in questa procedura è perchè la Collection contiene già l'elemento che si sta aggiungendo)

se non c'è errore

viene incrementata una matrice a due dimensioni

nella prima dimensione viene memorizzata la parola trovata

nella seconda dimensione viene posto il contatore (il numero 1)

terminata questa operazione si ordina la matrice

alla fine viene scritto il contenuto della matrice nell'intervallo desiderato

 

Questa che segue è la routine completa

Sub ContaParoleOrdinato()
Dim Elenco As New Collection
Dim R, R1, Contatore
Dim Frase As String
Dim Parole As Variant
Dim Lista()
Frase = Range("A1")
Parole = Split(Frase, " ")
On Error Resume Next
For R = LBound(Parole) To UBound(Parole)
       Elenco.Add Parole(R), CStr(Parole(R))
       If Err <> 0 Then
          For R1 = 1 To Elenco.Count
             If LCase(Elenco(R1)) = LCase(Parole(R)) Then
                Lista(2, R1) = Lista(2, R1) + 1
             End If
          Next
          Err = 0
       Else
          Contatore = Contatore + 1
          ReDim Preserve Lista(1 To 2, 1 To Contatore)
          Lista(1, Contatore) = Parole(R)
          Lista(2, Contatore) = 1
       End If
Next
On Error GoTo 0
For R = 1 To UBound(Lista, 2) - 1
       For R1 = R + 1 To UBound(Lista, 2)
          If Lista(2, R) < Lista(2, R1) Then
             Var1 = Lista(1, R)
             Lista(1, R) = Lista(1, R1)
             Lista(1, R1) = Var1
             Var1 = Lista(2, R)
             Lista(2, R) = Lista(2, R1)
             Lista(2, R1) = Var1
          End If
       Next
Next
For R = 1 To UBound(Lista, 2)
Cells(R, 5) = Lista(1, R)
Cells(R, 6) = Lista(2, R)
Next
End Sub

Cerchiamo di esaminare alcuni passaggi del codice che potrebbero restare oscuri.

 

Prima parte : acquisizione dei dati

Parole = Split(Frase, " ")

separa tutte le parole contenute in Frase usando il carattere separatore spazio

 

Seconda parte: rielvamento dati

il dato è già stato acquisito

If Err <> 0 Then

se è stato sollevato l'errore lo determiniamo leggendo il valore della variabile di sistema Err: in questo caso la parola è stata già inserita nella Collection, quindi occorre incrementarne il conteggio
in questo caso dobbiamo trovare la sua posiazione nella Collection per incrementarne l'occorrenza; questo lavoro viene eseguito dal seguente ciclo:

For R1 = 1 To Elenco.Count
If LCase(Elenco(R1)) = LCase(Parole(R)) Then
Lista(2, R1) = Lista(2, R1) + 1
End If
Next
Err = 0

in questo ciclo notiamo

LCase(Elenco(R1)) = LCase(Parole(R))

si usa la funzione LCase per rendere il confronto non sensibile alle maiuscole e minuscole

Lista(2, R1) = Lista(2, R1) + 1

Lista() è una matrice a due dimensioni: nella prima dimensione abbiamo memorizzato la parola trovata e nella seconda dimensione le sue occorrenze; con questa istruzione viene incrementata di una unità le occorrenze della parola nella frase.

il dato è appena acquisito

Fin qui se viene sollevato un errore per il tentativo di duplicare un elemento nella Collection. Ma se l'errore non viene sollevato l'elemento viene aggiunto con successo nella Collection. In questo caso entriamo nella porzione Else del costrutto If ... End If

Contatore = Contatore + 1
ReDim Preserve Lista(1 To 2, 1 To Contatore)
Lista(1, Contatore) = Parole(R)
Lista(2, Contatore) = 1

viene incrementata la seconda dimensione della matrice

Lista(1, Contatore) = Parole(R)

nella prima dimensione della matrice viene aggiunto l'elemento corrente appena accettato dalla Collection:

Lista(2, Contatore) = 1

nella seconda dimensione della matrice viene memorizzato il numero 1 che rappresenta la prima occorrenza dell'elemento appena aggiunto

 

Terza parte: ordinamento dei dati in base alle loro occorrenze

Se vogliamo che il nostro elaborato venga visualizzato in ordine crescente o decrescente dobbiamo affidarci ad uno degli algoritmi di ordinamento di cui possiamo disporre. Se i dati sono pochi possiamo affidarci senz'altro al Bubble Sort.

Il bubble sort (letteralmente: ordinamento a bolle) è un semplice algoritmo di ordinamento particolarmente indicato per l'ordinamento di array. Non si tratta di un algoritmo particolarmente efficiente. Tuttavia è piuttosto noto e utilizzato (sia in ambito didattico che da parte di programmatori professionisti) in virtù della sua semplicità. Come tutti gli algoritmi di ordinamento, può essere usato per ordinare dati di un qualsiasi tipo. Il nome dell'algoritmo è dovuto al fatto che, durante l'applicazione del procedimento, i valori vengono spostati all'interno dell'array con una dinamica che ricorda il movimento delle bollicine in un bicchiere di champagne.

L'ordinamento a bolle o bubble sort consiste nel raggiungere l'ordinamento attraverso il confronto del primo elemento con tutti i rimanenti (N-1 elementi), eseguendo i dovuti scambi e ripetendo l'operazione per tutti i restanti N-1 elementi. In tal modo l'elemento più piccolo (o più grande, a seconda del tipo di ordinamento che vogliamo: ascendende o discendente) viene a galla come una bolla (da cui il nome di ordinamento a bolle) e quindi a trovarsi in cima all'elenco.

Queste sono le istruzioni usate per l'ordinamento:

For R = 1 To UBound(Lista, 2) - 1
For R1 = R + 1 To UBound(Lista, 2)
If Lista(2, R) < Lista(2, R1) Then
Var1 = Lista(1, R)
Lista(1, R) = Lista(1, R1)
Lista(1, R1) = Var1
Var1 = Lista(2, R)
Lista(2, R) = Lista(2, R1)
Lista(2, R1) = Var1
End If
Next
Next

Come si può desumere dal listato del programma, il bubble sort consiste essenzialmente in due cicli for nidificati con un test (l'istruzione if) per confrontare due elementi.

In questo caso vogliamo che il valore più grande salga in cima alla lista ed è per questo che eseguiamo il confronto con:

If Lista(2, R) < Lista(2, R1) Then

Questo è tutto. Spero di essere stato chiaro. In caso contrario sono qui.

 

Mike