Cercare una determinata parola sul foglio di lavoro. Uso delle Funzioni InStr , Len, delle Proprietà SelLenght e SelStart e del Metodo SetFocus. - dal 04/09/04 pagina vista: volte

Per mie necessità nell'ottenere un programma che mi consentisse di realizzarmi un "Indice di voci" trovando una parola in una pagina di testo, mi è venuto in mente che le procedure seguite potevano interessare altre necessità: ho pensato per esempio ad un database di un magazzino, dove si voglia trovare il Codice di un'Articolo, di cui sappiamo o ci ricordiamo una parola contenuta nella Descrizione Articolo, oppure un database di una Libreria, dove si voglia rintracciare un libro attraverso la ricerca di una parola contenuta in un campo Recensione, o ancora un'Agenzia immobiliare che per rintracciare un'immobile svolga una ricerca su una parola contenuta in un ipotetico campo Notazioni, (ascensore, 2 bagni, giardino, ecc. ecc.). Insomma, i casi per poter usare questi suggerimenti non mancano certamente, oltre al fatto di cercare di completare alcuni articoli presenti sul sito circa la possibilità di crearsi degli elenchi di file presenti sul nostro hard-disk, e perchè sempre più usiamo Excel come database, inserendo nelle celle frasi a volte molto lunghe, presento una nuova procedura (per questi siti) di ricerca: rintracciare una determinata parola in tutte le celle del foglio di lavoro, con evidenzazione  DELLA PAROLA CERCATA. Utilità questa da poter abbinare ad alcune procedure come quelle trattate negli articoli (in questa sezione) "Usare Shell + Run", "Usare l'HyperLinks" e anche "DriveList,DirList, FileList", oppure in elenchi nei quali, per necessità gestionali, si usino celle contenenti frasi lunghe, come potrebbe essere un campo "Descrizione" oppure "Argomento trattato", oppure "Recensioni", campi insomma dove per necessità visive, limitiamo la larghezza del campo e dove risulta impossibile leggere tutto il testo inserito. Sappiamo infatti che se in una cella scriviamo una frase dal testo lungo, Excel ce lo mostra nella sua lunghezza, ma se nella cella a destra inseriamo un valore, la frase "rientra" nella cella di residenza (al di là delle opzioni di Controllo testo). Un esempio, nella cella A2 abbiamo un testo lungo che fuoriesce dalla cella, come scriviamo un qualsiasi valore nella cella a lato (B2), il testo rientra:

Questo comportamento ci impedirebbe di leggere in una ricerca manuale la parola America. Ma potrebbe essere anche il caso di colonne impostate con larghezza sufficiente a contenere il testo, ma su fogli con database molto ampi, dove per trovare tutte le parole cercate, dovremmo scorrere centinaia o migliaia di righe di dati.

Ora, per trovare una parola all'interno di un testo, meglio se cominciamo a chiamarlo "stringa di testo", e abbreviato "stringa", possiamo ricorrere all'Operatore LIKE (vedi articolo sull'altro sito, sezione vba), che con una routine veloce veloce, ci consentirebbe di trovare la cella con la stringa contenente la parola cercata, MA NON di evidenziare la parola stessa all'interno della stringa, che è lo scopo di questo articolo. Vediamo comunque una routine con Like, dal sapore un pò goliardico per il tipo di domanda posta, che può comunque servire egregiamente dato che il contenuto di ogni cella occupata da una stringa in cui compaia la parola che cerchiamo, viene evidenziato nella barra della formula, e tanto basterebbe per riconoscere se la stringa è quella che cerchiamo:

Ricordo che queste ricerche sono CaseSensitive, cioè sensibili a maiuscole/minuscole; per rendere la ricerca Non CaseSensitive, inseriamo nella sezione Dichiarazioni - Generale del modulo che ospita la macro, questa semplice istruzione:

Option Compare Text

-------------------------------------------------------------------------------------------------------

Sub CercaParola2()
Dim CL As Object

'sotto: con "zona" impostiamo l'area di ricerca che con UsedRange comprenderà tutte le celle che 'contengono dati, sul foglio attivo.
Set zona = ActiveSheet.UsedRange
dimmi = InputBox("Cosa Cavolo cerchi?")
'usiamo una InputBox per memorizzare con '"dimmi",  la parola da cercare
If dimmi = "" Then Exit Sub
'se non scriviamo niente nella InputBox usciamo dalla routine
For Each CL In zona
 'iniziamo il ciclo di ricerca in ogni cella dell'area "zona"

'sotto: usiamo Like che, impostato con due asterischi, prima e dopo la parola scritta nell'inputbox, ci 'consentono di trovare la parola "qualunque cosa ci sia prima" e "qualunque cosa ci sia dopo" la parola 'stessa. Quindi l'istruzione dice: se il valore che è nella cella, "Contiene" la parola cercata, allora....
If CL.Value Like "*" & dimmi & "*" Then
CL.Select  
'si seleziona la cella (e il suo contenuto lo si vede nella barra della formula)
dove = CL.Address(rowabsolute:=False, columnabsolute:=False)
'si prende con "dove" il riferimento 'alla cella, poi si pone la domanda se vorremo proseguire (sotto) :
Dim idomanda As Integer
idomanda = MsgBox("Trovato " & dimmi & " in " & dove & ". Vuoi Cercare ancora?", vbYesNo)
If idomanda = vbNo Then
'se risponderemo che non vogliamo più cercare, si esce dalla routine
Exit Sub
End If
 'si chiude il se relativo a If idomanda
End If 
'si chiude il se relativo If CL.Value
Next 
'altrimenti si prosegue la ricerca fino alla fine delle celle occupate
End Sub

Ed ora passiamo a vedere il come evidenziare una parola all'interno di una stringa. Useremo ora le Funzioni InStr , Len, le Proprietà SelLenght e SelStart e il Metodo SetFocus per una TextBox (ActiveX) posta in una UserForm. Abbiamo bisogno di sfruttare caratteristiche di una TextBox disponibili SOLO se la TextBox ActiveX è nel suo ambiente naturale. In particolare il metodo SetFocus NON si applica ad una TextBox ActiveX posta ("prestata") sul foglio di lavoro. Ma vediamo prima funzioni e proprietà:

  • InStr - Funzione. Restituisce un valore Variant (Long) che specifica la posizione della prima occorrenza di una stringa (o parola) all'interno di un'altra. La sua sintassi è questa (tralascio gli argomenti opzionali, tra parentesi quadre):  InStr([inizio, ]stringa1, stringa2[, confronto]) - dove: stringa1 è l'oggetto che contiene la stringa (tutto il testo) DOVE cercare, stringa2 è l'oggetto DA cercare, cioè la parola da cercare all'interno del testo.

  • Len - Funzione. Restituisce un valore (Long) che contiene il numero di caratteri presenti in una stringa o il numero di byte necessari per memorizzare una variabile. La sua sintassi è questa : Len(stringa | nomevariabile). E possibile usare uno solo dei due argomenti nella funzione, e noi useremo stringa. Con Len misuriamo da quanti caratteri è formata la parola da cercare.

  • SelStart - Proprietà, si applica solo ad una TextBox e/o ComboBox ActiveX. Indica il punto di inizio del testo selezionato oppure il punto di inserimento se non è selezionato alcun testo. La sua sintassi è : oggetto.SelStart [= Long]. Oggetto è sempre necessario (sarà la nostra textbox), [Long] è facoltativo. e dovrà essere una espressione numerica che indica il punto di inizio del testo selezionato. Nel nostro esempio sarà rappresentato dal valore restituito dalla funzione InStr.

  • SelLenght - Proprietà, si applica solo ad una TextBox e/o ComboBox ActiveX. Indica il numero di caratteri selezionati in una casella di testo o nell'area di immissione del testo di una casella combinata. La sua sintassi è : oggetto.SelLength [= Long] . Oggetto è sempre necessario (sarà la nostra textbox), [Long] è facoltativo, e dovrà essere una espressione numerica che indica il numero di caratteri selezionati. Nel nostro caso sarà la funzione Len.

  • SetFocus - Metodo, si applica a tutti gli "Oggetti" ActiveX inseriti su UserForm (non disponibile se un oggetto ActiveX viene inserito sul foglio di lavoro). Serve per spostare lo stato attivo sull'istanza corrente dell'oggetto. La sua sintassi è semplice: oggetto.SetFocus . Oggetto in questo caso sarà la nostra TextBox.

Bene, se avete seguito fin qui, non mollate che ora viene il bello. La routine che stiamo impostando, ha come compito principale quello di evidenziare una parola in una stringa di testo, e tanto per intenderci, cercando la parola "America", vogliamo un risultato del genere:

e perchè ciò avvenga, è necessario che l'oggetto in cui si trova la stringa (una TextBox) e la parola trovata, mantenga lo stato attivo (cioè il Focus). Questa necessità non è gestibile in due casi :

  • Se si inserisce una TextBox (ActiveX) direttamente sul foglio di lavoro. In questo caso la TextBox non possiede la proprietà TabIndex nè la proprietà TabStop e quindi rifiuta il SetFocus necessario per selezionare la parola cercata, generando un errore. Non è possibile usare il Select perchè servirebbe solo a selezionare la TextBox ma non a porvi il Focus.

  • Useremo quindi una UserForm per inserirci la TextBox  dove visualizzare il contenuto della cella contenente la stringa con la parola cercata, ottenendo il risultato voluto. Abbiamo anche bisogno però di una istruzione che preveda la continuazione della ricerca in tutte le celle occupate del foglio. Per fare questo ci dovremo servire di una finestra di dialogo che ci ponga una domanda: se vogliamo continuare o fermare la ricerca. E qui troviamo il secondo ostacolo al nostro progetto: infatti la comparsa di una finestra di dialogo immediatamente seguente al testo trovato, TOGLIE il Focus alla parola appena selezionata, prendendo lo stato attivo, e noi col piffero che identificheremo subito detta parola, per stabilire se la stringa è quella che ci interessa, specie se il testo è molto lungo, e la parola magari è alla fine della stringa.

Chiariti questi due punti, iniziamo a vedere come sono composte le istruzioni: per chiamare la routine useremo un pulsante posto sul foglio di lavoro. La macro viene posta in un modulo standard, useremo delle variabili che dovranno essere "visibili" anche fuori dal modulo (anche dalla UserForm) e quindi nella sezione Dichiarazioni  -  Generale del modulo, inseriremo queste due istruzioni:

  • Option Compare Text - che ha il compito di rendere Non CaseSensitive  la ricerca della parola ( America sarà così trovata anche se come ricerca useremo america (con la minuscola) o AMERICA).

  • Option Explicit - obbliga a "dichiarare" una variabile. Dovremo in questo caso obbligatoriamente Dimensionare (Dim) il "tipo" (As) di variabile. Noi useremo tutte variabili di "tipo" Variant, che possono essere non dichiarate, e se non dichiarate, vengono di default assunte come tali.

  • poi imposteremo la proprietà ShowModal della UserForm a False. Questo ci consente di poter utilizzare il foglio senza essere bloccati dalla presenza della UserForm.

Useremo una InputBox per reperire la parola da cercare, per definire l'area in cui eseguire la ricerca useremo UsedRange che ci consente di reperire tutte le celle del foglio con dati, anche se non contigue o distanti, e lo "spazzolamento" delle celle lo faremo con un ciclo For Each..Next. Useremo poi la funzione Timer : impostando il tempo in secondi, regoleremo la durata tra la visualizzazione della stringa con la parola cercata, e la comparsa del messaggio che ci chiederà se continuare la ricerca o meno. Io per consentire di modificare il tempo ho inserito una seconda TextBox nella UserForm, con la sua proprietà Text impostata a 5 (secondi). Questo valore è il valore assegnato alla pausa del Timer; potrete modificarlo inserendo un valore fisso diverso anche direttamente nella riga dell'istruzione, oppure richiedere con un'altra inputbox il tempo che giudicherete a voi necessario. (ricordo che questa pausa deve servire per riuscire a leggere tutto il testo visualizzato; con testi molto lunghi dove l'individuazione della parola può richiedere più tempo, sarà necessario impostare tempi di pausa più lunghi.). Cominciamo a vedere questa benedetta routine, con le spiegazioni (in verde):

Sub CercaParola()

'dichiarazione variabili
Dim CL As Object
Dim Zona
Dim Dimmi, RifCella
Dim Stringa, Parola, Dove

'impostiamo con "Zona" l'UsedRange del foglio1 (tutte le celle con dati)
Set Zona = Worksheets(1).UsedRange 

'con "Dimmi" tramite l'inputbox, memoriziamo la parola da cercare
Dimmi = InputBox("Cosa Cavolo Cerchi?", "Inserisci la parola da cercare")

If Dimmi = "" Then Exit Sub  'se non scriviamo niente o premiamo Annulla, si esce dalla routine

'iniziamo il ciclo per "spazzolare" tutta l'area identificata con "zona"
For Each CL In Zona
' "Stringa" è la stringa DOVE cercare è sarà il testo contenuto nella cella (CL) ora spazzolata
Stringa = CL.Value
'con Parola abbiamo la parola da cercare nella stringa, reperita con Dimmi (InputBox)
Parola = Dimmi

'con Dove otteniamo la posizione di Parola all'interno di Stringa tramite InStr
Dove = InStr(Stringa, Parola)

'se Dove esiste, allora
If Dove Then
'si fa apparire la UserForm1
UserForm1.Show

'si seleziona la cella trovata
CL.Select

'si prende l'indirizzo (Address) della cella
RifCella = CL.Address(rowabsolute:=False, columnabsolute:=False)

'e si riporta nella Label1 che ci indicherà quale cella contiene tutta la frase con la parola cercata
UserForm1.Label1.Caption = "In " & RifCella
'
quindi si rende la textbox1 sulla userform uguale al contenuto della cella ora selezionata
UserForm1.TextBox1 = CL.Value

'indi si imposta il punto di inizio del testo da selezionare. Si scala di un valore per comprendrvi 'anche la lettera iniziale della parola
UserForm1.TextBox1.SelStart = Dove - 1

'poi si indica il numero dei caratteri che vogliamo selezionare
UserForm1.TextBox1.SelLength = Len(Parola)
'e alla fine poniamo il Focus su questa selezione di cui abbiamo l'inizio e la lunghezza
UserForm1.TextBox1.SetFocus
'dimensioniamo le variabili  per il Timer
Dim PauseTime, Start,  TotalTime
'impostiamo il tempo totale della pausa, nell'esempio preso dalla proprietà Text della TextBox2
TotalTime = UserForm1.TextBox2.Text
PauseTime = TotalTime
' Impostiamo la durata della pausa
Start = Timer
' Impostiamo l'inizio del Timer

'fino a che il Valore di Timer è inferiore al suo valore più la pausa
Do While Timer < Start + PauseTime
DoEvents
 'si passa con DoEvents il controllo ad altri processi
Loop 
'gira, cioè stai in pausa
'scaduto il tempo si chiude la UserForm
Unload UserForm1
'poi si pone la domanda se si vuole proseguire
Dim dammi As Integer
dammi = MsgBox("Proseguire la ricerca ?", vbYesNo)

'se la risposta sarà no
If dammi = vbNo Then
'si seleziona la cella
CL.Select
Exit Sub
'e si esce dalla routine
End If
'nel caso si sia risposto Si, di voler continuare, si prosegue al Next che continua il ciclo fino alla 'fine di "Zona"

'impostiamo anche un controllo che ci avvisi quando avremo "spazzolato" l'ultima cella di "zona" 'che la ricerca è terminata.
If CL = Zona.SpecialCells(xlCellTypeLastCell) Then GoTo 10
End If

Next
10:

MsgBox "Ricerca Terminata"
End Sub

Una variante per gestire meglio il tempo della pausa necessaria alla lettura del testo, può essere questa:

  • Si imposta un tempo di pausa lungo, per esempio 30 secondi (modificando la proprietà Text della TextBox2 che rappresenta il valore in secondi assegnato a TotalTime)

  • si aggiunge un CommandButton sulla UserForm, e nel suo evento Click inseriamo l'istruzione per chiudere la Form: la potremo chiudere appena ci siamo resi conto se la stringa che appare nella textbox1 è quella che interessa o meno, anticipando (con la riga in grassetto inserita al punto successivo)  la continuazione della ricerca o la selezione della cella così trovata:

  • Private Sub CommandButton1_Click()
    Unload Me
    End Sub

  • Poi aggiungeremo una riga di istruzione nella procedura Timer che controlli se la UserForm è visibile oppure no; nel caso non sia visibile si esce dal ciclo Do While con Exit Do, e si prosegue (in grassetto la modifica):

  • Do While Timer < Start + PauseTime
    DoEvents
     'si passa con DoEvents il controllo ad altri processi

  • If UserForm1.Visible = False Then Exit Do
    Loop 

Vediamo le immagini; la InputBox per l'introduzione della parola da cercare:

e la userform con il testo visualizzato e la parola che abbiamo cercato evidenziata, l'indicazione di quale cella è selezionata, la casella per modificare il  tempo di pausa (se siete veloci):

Per poter ospitare eventuali testi lunghi, la proprietà MultiLine della TextBox1 è impostata a True, e la proprietà ScrollBars impostata a 2 (barre di scorr. verticali). Le barre compariranno se il testo visualizzato occuperà più righe rispetto alla dimensione che avremo scelto per la TextBox .

Per riallacciarmi ad discorso iniziale, legato a possibili ricerche su un determinato campo e non a tutto il foglio (come nella routine presentata) sarà sufficiente reimpostare la "Zona", quindi un esempio che effettui la ricerca in tutte le celle della colonna D, sarà:

  • Set Zona = Worksheets(1).Range("D : D") 

Se poi vogliamo identificare tutti i dati correlati relativi alla parola trovata, dopo aver risposto NO alla richiesta di continuare la ricerca, possiamo modificare la seconda istruzione CL.Select   in : CL.EntireRow.Select e verrà selezionata l'intera riga.

Buon lavoro.

prelevato sul sito www.ennius.altervista.org