Connessione al database con Visual Basic NET? Lo trovi su Opentraining.it Visual Basic Italia
PRINCIPALE > CORSO DI VISUAL BASIC

Eseguire una ricerca veloce nell' archivio delle risorse di Visual Basic Italia®: 

Preso dall'archivio...

Premere il pulsante sotto per accedere direttamente ad un articolo o ad un esempio preso in modo casuale dall'archivio.



Ultimo e-book pubblicato:

"INTRODUZIONE AI CSS"

Lo scopo del CSS language è quello di controllare lo stile dei vari elementi che concorrono a formare un
documento HTML.
Si può operare in tre modi collegamento ad un foglio di stile esterno;definizione degli stili all'inizio
del documento utilizzo della proprietà style all'interno di un Tag HTML (embedded style). Questo e-book introduttivo
servirà per apprendere tali nozioni fondametali dei fogli di stile.

Prezzo: € 0.0.
Presentazione:
REAL SOFTWARE RILASCIA LA VERSIONE 5.0 di REALbasic per Windows






Gorizia, 5 maggio 2003 - Active, distributore in esclusiva di REALSoftware, Austin, Tx, annuncia la disponibilità di REALbasic 5.0 per Windows, uno strumento per lo sviluppo semplice da usare che permette agli utenti Windows di tutti i livelli di creare applicazioni personalizzate e di compilarle sia per la piattaforma Windows che per quella Macintosh.
[>>]

http://www.active-software.com

 

Contatti. Utilizzare l'email generica per domande relative al sito:
Porre domande relative al sito
oppure scrivere ad un responsabile di area.
Responsabile del sito: >Andrea Martelli
Responsabile area "Corso di VB":
> Giorgio Abraini

Corso di Visual Basic: lezione 26

Questa lezione, consultata da 15448 utenti, è stata giudicata di ottimi contenuti , con un'esposizione perfettamente comprensibile e con un livello di approfondimento buono da 25 votanti.


Lezione 26

Cominciamo questa lezione correggendo quella precedente: nella routine cmdTrova_Click era infatti nascosto (anzi, era abbastanza evidente) un bug di cui avreste dovuto accorgervi: la parte di codice destinata a cercare l'ultimo testo puro in realtà non trova l'ultimo, ma quello successivo al primo. La correzione è molto semplice:

'ultimo testo "puro"
lFine = Len(txtTrova.Text)
Do While Mid$(txtTrova.Text, lFine, 1) Like "[*?#]" And lFine > 1
lFine = lFine - 1
Loop
lInizio = IIf(lFine > 1, lFine, 2)
Do
lInizio = lInizio - 1
Loop Until Mid$(txtTrova.Text, lInizio, 1) Like "[*?#]" Or lInizio <= 1
If Mid$(txtTrova.Text, lInizio, 1) Like "[*?#]" Then
sTestoPuro(1) = Mid$(txtTrova.Text, lInizio + 1, lFine - lInizio)
Else
sTestoPuro(1) = Mid$(txtTrova.Text, lInizio, lFine - lInizio + 1)
End If

arriverebbe fino a zero generando un errore nella funzione Mid$(); per lo stesso motivo la variabile lInizio è inizializzata a 2 se lFine è uguale a 1.
Quando lFine=1, alla fine del secondo loop anche lInizio è uguale a 1, così che sTestoPuro(1) diventa la stringa vuota. La If finale serve a distinguere il caso in cui c'è un solo testo puro: in tal caso la ricerca si ferma quando lInizio=1 e per estrarre correttamente il testo puro occorre capire se il primo carattere è un carattere jolly (quindi il testo puro parte dal secondo carattere) oppure no (quindi il testo puro parte dal primo carattere).
Se invece la ricerca si ferma prima (ovvero dopo il primo carattere, dato che si parte dal fondo) significa che essa è terminata perché abbiamo incontrato un carattere jolly: non ci sarebbe bisogno di eseguire la If, ma per evitarlo avremmo dovuto introdurre un ulteriore controllo sul valore di lInizio (If lInizio=1 then …).
La nostra routine trova sempre il primo e l'ultimo testo puro, anche nel caso in cui questi coincidono (ad es. quando l'utente vuole cercare "?pippo#" o semplicemente "pippo"): se ciò si verifica, per evitare problemi nella ricerca del testo è opportuno impostare l'ultimo testo puro alla stringa nulla, in modo da essere consapevoli che di testo puro effettivamente ce n'è uno solo:

If InStr(1, txtTrova.Text, sTestoPuro(0), vbBinaryCompare) = _
InStrRev(txtTrova.Text, sTestoPuro(1), , vbBinaryCompare) Then
'il primo e l'ultimo testo puro coincidono
sTestoPuro(1) = ""
End If

Per verificare la coincidenza dei due testi non basta che siano uguali (l'utente potrebbe cercare, ad es., "pippo*pippo"): condizione necessaria e sufficiente affinché i due testi siano coincidenti è che la loro posizione all'interno della stringa inserita dall'utente sia la stessa; il primo testo lo cerchiamo a partire dall'inizio della stringa con la funzione InStr, l'ultimo lo cerchiamo a partire dal fondo con la funzione InStrRev: se le due posizioni sono uguali, i due testi coincidono.
Fatto ciò, potremmo cominciare a cercare il testo, ma non abbiamo ancora considerato il caso in cui il primo e l'ultimo testo puro sia rispettivamente preceduto o seguito da caratteri jolly; in tal caso occorre infatti verificare se l'utente cerca anche una cifra oppure no.
Gli asterischi, potendo rappresentare anche zero caratteri, non influiscono concretamente sulla ricerca; i punti di domanda non danno indicazioni su quale carattere cercare, pertanto basta verificare che ci siano tanti caratteri quanti sono i punti di domanda specificati nella stringa da cercare. Invece i cancelletti rappresentano una cifra, e non possono essere liquidati tanto facilmente: la cosa più conveniente è trattarli come se fossero "testo puro": quindi se l'utente specifica, ad es., "??*#pippo*?piero##", anziché limitarsi a trovare "pippo" e "piero" occorre trovare un "pippo" preceduto da una cifra e un "piero" seguito da due cifre. In realtà, le cose sono un po' più semplici: basta cercare due cifre all'interno del testo, assicurarsi che la prima cifra sia preceduta da almeno due caratteri, e confrontare l'intero testo contenuto tra questi limiti con la stringa cercata dall'utente: l'operatore like ci dirà se i due testi corrispondono oppure no.

Utilizziamo un vettore lCifra(1) per indicare quanti caratteri devono precedere la prima cifra e quanti devono seguire l'ultima: nell'esempio, lCifra(0) sarebbe uguale a 2 mentre lCifra(1)=0; si tratta del minimo numero di caratteri per soddisfare la sequenza cercata dall'utente, in realtà la prima cifra potrebbe essere preceduta anche da 10 caratteri o l'ultima seguita da 10 caratteri.
Specifichiamo il valore -1 per indicare che non dobbiamo cercare cifre: ad es. nel caso "?pippo*piero*#" sarebbe lCifra(0)= -1, lCifra(1)=0.

Analogamente, utilizziamo un vettore lCarattere(1) per indicare quanti caratteri devono precedere il testo puro iniziale o seguire il testo puro finale: questa informazione ci servirà solo nel caso in cui la stringa da cercare non contenga numeri, ovvero caratteri "#".
In un caso come "?pippo#", sarà lCifra(0)=-1, lCifra(1)=0, lCarattere(0)=1, lCarattere(0)=0; se non usassimo lCarattere, non potremmo sapere che prima di "pippo" ci deve essere almeno un carattere, anche se non è una cifra; lCarattere(1) non sarà utilizzato in quanto già lCifra(1) ci dà tutte le informazioni necessarie.

Ora possiamo cercare il testo. L'algoritmo è relativamente semplice: se il primo testo puro è preceduto da una cifra, cerchiamo una cifra, altrimenti cerchiamo il testo puro iniziale; una volta trovato, cerchiamo da quel punto in poi il testo puro finale o la cifra che lo deve seguire.
A questo punto confrontiamo il testo contenuto tra gli estremi iniziale e finale e lo confrontiamo con la stringa definita dall'utente: se l'esito è negativo, continuiamo la ricerca del testo puro finale o della cifra finale, ricorsivamente, fino alla fine del file.
Se invece l'esito è positivo, evidenziamo il testo trovato e ci prepariamo a un'ulteriore ricerca.

lInizio = 0: lFine = 0
lTipoRicerca = IIf(chkCaseSens.Value = vbChecked, vbBinaryCompare, vbTextCompare)
With frmNotePad.txtFile
Do
If lCifra(0) >= 0 Then
'cerca la prima cifra
Do
lInizio = lInizio + 1
Loop Until Mid$(.Text, lInizio, 1) Like "#" Or lInizio > Len(.Text)
If lInizio > Len(.Text) Then
lInizio = 0
Else
lFine = lInizio
End If
Else

If Len(sTestoPuro(0)) Then
'cerca il testo puro iniziale
lInizio = InStr(lInizio + 1, .Text, sTestoPuro(0), lTipoRicerca)
End If
lFine = lInizio + Len(sTestoPuro(0))-1
End If
If
lInizio Then
Do
If
lCifra(1) >= 0 Then
'cerca l'ultima cifra
Do
lFine = lFine + 1
Loop Until Mid$(.Text, lFine, 1) Like "#" Or lFine > Len(.Text)
If lFine > Len(.Text) Then lFine = 0
Else
LFine = lFine+1
'cerca il testo puro finale
If Len(sTestoPuro(1)) Then
lFine = InStr(lInizio + 1, .Text, sTestoPuro(1), lTipoRicerca)
End If
End If

If lFine = 0 Then
Exit Do
Else

lInizioTemp = lInizio - IIf(lCifra(0) < 0, IIf(lCarattere(0) < 0, 0, lCarattere(0)), lCifra(0))
If lCifra(1) >= 0 Then
lFineTemp = lFine + lCifra(1)
Else
lFineTemp = lFine + Len(sTestoPuro(1)) + IIf(lCarattere(1) < 0, 0, lCarattere(1)) - 1
End If
End If
DoEvents

sTestoTrovato = Mid$(.Text, lInizioTemp, lFineTemp - lInizioTemp+1)
Loop Until IIf(lTipoRicerca = vbBinaryCompare, (sTestoTrovato Like txtTrova.Text), UCase$(sTestoTrovato) Like UCase$(txtTrova.Text))

If lFine Then
.SelStart = lInizioTemp - 1
.SelLength = lFineTemp - lInizioTemp+1
End If
Else

'cifra o testo iniziale non trovati
MsgBox "Testo non trovato", vbOKOnly + vbExclamation, App.Title
End If
Loop While (lFine = 0) And (lInizio < Len(.Text))

End With


Prima di tutto inizializziamo i due contatori lInizio e lFine, poi per comodità memorizziamo in lTipoRicerca se la ricerca deve essere case sensitive oppure no; dopo aver cercato la prima cifra o il primo testo puro, parte un ciclo per la ricerca dell'ultima cifra o dell'ultimo testo puro: se il testo non viene trovato, la variabile lFine è posta a 0 e il ciclo termina. Altrimenti gli estremi iniziali e finali del testo vengono aggiustati per tener conto dei caratteri identificati dai punti di domanda nella stringa specificata dall'utente; dopodiché, l'operatore like ci dice se il testo corrisponde a quello cercato oppure no: in quest'ultimo caso, la ricerca continua a partire dal punto in cui siamo arrivati.
Se invece il testo corrisponde, esso viene evidenziato nella finestra frmNotePad.
Se il testo non viene trovato per tutto il file, viene visualizzato un messaggio di errore: la proprietà App.Title indica il titolo dell'applicazione (si imposta tramite le proprietà del progetto, nella scheda "crea").
Nella routine ci sono due loop annidati, che idealmente hanno il compito di cercare il testo puro iniziale (il loop esterno) e quello finale (il loop interno); essi corrispondono a questa logica:

1) se c'è un testo puro iniziale, lo cerco: se lo trovo, passo al punto 2, altrimenti genero un errore;
2) se c'è un testo puro finale, lo cerco: se lo trovo, passo al punto 3, altrimenti torno al punto 1 cercando il successivo testo puro iniziale;
3) se il testo contenuto tra i due testi puri corrisponde a quello cercato dall'utente, lo seleziono; altrimenti torno al punto 2 e cerco il successivo testo puro finale

Detto in altri termini, prima cerco il testo puro iniziale: se lo trovo, procedo da quel punto in poi cercando il testo puro finale finché trovo un testo che globalmente corrisponda a quello cercato dall'utente (loop interno); se non lo trovo, torno all'inizio (loop esterno) e cerco il testo puro iniziale successivo a quello trovato nell'iterazione precedente, dopodiché ricomincio la ricerca del testo puro finale, a partire dalla posizione del testo puro iniziale appena trovato.
L'errore "testo non trovato" viene perciò generato solo quando non trovo più un testo puro iniziale entro la fine del file, altrimenti devo continuare la ricerca del testo puro finale.
Questa situazione è controllata dalla condizione del loop esterno: (lFine = 0) And (lInizio < Len(.Text)); se non ho trovato un testo puro finale (lFine=0) e se non ho ancora cercato per tutto il file (lInizio<Len(.Text)), allora ripeto la ricerca del testo puro iniziale.

Per verificare la congruenza del testo trovato con quello cercato dall'utente, l'operatore Like viene utilizzato in due modalità diverse a seconda che la ricerca sia case sensitive oppure no: se vi ricordate, nella lezione scorsa avevo indicato l'opportunità di specificare l'istruzione Option Compare Binary nel form frmTrova; pertanto, se la ricerca è case sensitive è sufficiente usare l'operatore like, ma se la ricerca non è case sensitive, occorre ignorare la specifica Option Compare Binary usando la funzione Ucase$(); ecco perché la condizione del loop interno dipende dall'istruzione IIf(lTipoRicerca=vbBinaryCompare…).
L'istruzione With…End With indica che all'interno del blocco è "sottinteso" l'oggetto frmNotePad.txtFile: è un modo per rendere più chiaro e leggibile il codice e per rendere più veloce il riferimento alle proprietà di quell'oggetto.
La routine appena vista consente di cercare il testo dall'inizio del file, il che significa che premendo più volte il pulsante "trova", la stringa trovata sarà sempre la stessa, la prima dall'inizio del file; per fare in modo che si possano cercare anche le successive occorrenze del testo, basta fare una semplicissima modifica: anziché inizializzare lInizio a zero, bisogna inizializzarlo alla posizione corrente del cursore nel file.
Questa posizione è data dalle proprietà SelStart e SelLength dell'oggetto TextBox, che indicano rispettivamente il numero del carattere iniziale del testo selezionato e il numero di caratteri selezionati: se ad es. nel testo "pippo e topolino" seleziono "po e to", risulterà SelStart=3 e SelLength=7; infatti SelStart inizia a contare da zero, nel senso che quando il cursore è proprio all'inizio del file aperto (prima della prima lettera), SelStart vale zero.
Tornando al nostro algoritmo, basta modificare la prima riga in questo modo:


With frmNotePad.txtFile
lInizio = .SelStart + .SelLength: lFine = 0

La riga di inizializzazione è stata portata all'interno del blocco With per comodità; lInizio è inizializzato alla posizione finale della selezione, se esiste un testo selezionato: questo perché l'algoritmo, quando trova il testo cercato dall'utente, lo seleziona. Se facessimo semplicemente lInizio=.SelStart, la ricerca partirebbe dal primo carattere della selezione, e quindi troverebbe ancora il testo già selezionato, e non quello successivo: in altre parole non avremmo risolto il nostro problema. Se fate qualche prova vi accorgerete che anche il vero blocco note e word funzionano allo stesso modo.
In conclusione, la nostra routine cmdTrova_Click, è la seguente:


Public Sub cmdTrova_Click()
Dim lTipoRicerca As Long
Dim lCifra(1) As Long
Dim
lCarattere(1) As Long
Dim
lInizio As Long
Dim
lFine As Long
Dim
lInizioTemp As Long
Dim
lFineTemp As Long
Dim
sTestoPuro(1) As String
Dim
sTestoTrovato As String

lInizio = 0: lFine = 0
Erase sTestoPuro
Erase lCifra

cmdTrova.Enabled = False
cmdChiudi.Enabled = False
Me.MousePointer = vbHourglass

Do
lInizio = lInizio + 1
Loop While Mid$(txtTrova.Text, lInizio, 1) = "*"

lFine = Len(txtTrova.Text)
Do While Mid$(txtTrova.Text, lFine, 1) = "*"
lFine = lFine - 1
Loop
txtTrova.Text = Mid$(txtTrova.Text, lInizio, lFine - lInizio + 1)

'primo testo "puro"
lInizio = 0
Do
lInizio = lInizio + 1
Loop While Mid$(txtTrova.Text, lInizio, 1) Like "[*?#]"
lFine = lInizio
Do
lFine = lFine + 1
Loop Until Mid$(txtTrova.Text, lFine, 1) Like "[*?#]" Or lFine > Len(txtTrova.Text)
sTestoPuro(0) = Mid$(txtTrova.Text, lInizio, lFine - lInizio)

lCifra(0) = InStr(1, Replace(Left$(txtTrova.Text, lInizio - 1), "*", ""), "#") - 1
lCarattere(0) = InStr(1, Replace(txtTrova.Text, "*", ""), sTestoPuro(0)) - 1

'ultimo testo "puro"
lFine = Len(txtTrova.Text)
Do While Mid$(txtTrova.Text, lFine, 1) Like "[*?#]" And lFine > 1
lFine = lFine - 1
Loop
lInizio = IIf(lFine > 1, lFine, 2)
Do
lInizio = lInizio - 1

Loop Until Mid$(txtTrova.Text, lInizio, 1) Like "[*?#]" Or lInizio <= 1
If Mid$(txtTrova.Text, lInizio, 1) Like "[*?#]" Then
sTestoPuro(1) = Mid$(txtTrova.Text, lInizio + 1, lFine - lInizio)
Else
sTestoPuro(1) = Mid$(txtTrova.Text, lInizio, lFine - lInizio + 1)
End If

lCifra(1) = Len(Replace(Mid$(txtTrova.Text, lFine + 1), "*", "")) - _
InStrRev(Replace(Mid$(txtTrova.Text, lFine + 1), "*", ""), "#")
If lCifra(1) = Len(Replace(Mid$(txtTrova.Text, lFine + 1), "*", "")) Then
lCifra(1) = -1
End If

lCarattere(1) = Len(Replace(txtTrova.Text, "*", "")) - _
InStrRev(Replace(txtTrova.Text, "*", ""), sTestoPuro(1)) - Len(sTestoPuro(1))

If InStr(1, txtTrova.Text, sTestoPuro(0), vbBinaryCompare) = _
InStrRev(txtTrova.Text, sTestoPuro(1), , vbBinaryCompare) Then
'il primo e l'ultimo testo puro coincidono
sTestoPuro(1) = ""
End If

With frmNotePad.txtFile
lInizio = .SelStart + .SelLength: lFine = 0
lTipoRicerca = IIf(chkCaseSens.Value = vbChecked, vbBinaryCompare, vbTextCompare)
Do
If lCifra(0) >= 0 Then
'cerca la prima cifra
Do
lInizio = lInizio + 1
Loop Until Mid$(.Text, lInizio, 1) Like "#" Or lInizio > Len(.Text)
If lInizio > Len(.Text) Then
lInizio = 0
Else
lFine = lInizio
End If
Else

If Len(sTestoPuro(0)) Then
'cerca il testo puro iniziale
lInizio = InStr(lInizio + 1, .Text, sTestoPuro(0), lTipoRicerca)
End If
lFine = lInizio + Len(sTestoPuro(0)) - 1
End If

If lInizio Then
Do
If
lCifra(1) >= 0 Then
'cerca l'ultima cifra
Do
lFine = lFine + 1
Loop Until Mid$(.Text, lFine, 1) Like "#" Or lFine > Len(.Text)
If lFine > Len(.Text) Then lFine = 0
Else
lFine = lFine + 1
'cerca il testo puro finale
If Len(sTestoPuro(1)) Then
lFine = InStr(lInizio + 1, .Text, sTestoPuro(1), lTipoRicerca)
End If
End If

If lFine = 0 Then
Exit Do
Else

lInizioTemp = lInizio - IIf(lCifra(0) < 0, IIf(lCarattere(0) < 0, 0, lCarattere(0)), lCifra(0))
If lCifra(1) >= 0 Then
lFineTemp = lFine + lCifra(1)
Else
lFineTemp = lFine + Len(sTestoPuro(1)) + IIf(lCarattere(1) < 0, 0, lCarattere(1)) - 1
End If
End If
DoEvents

sTestoTrovato = Mid$(.Text, lInizioTemp, lFineTemp - lInizioTemp + 1)
Loop Until IIf(lTipoRicerca = vbBinaryCompare, (sTestoTrovato Like txtTrova.Text), UCase$(sTestoTrovato) Like UCase$(txtTrova.Text))

If lFine Then
.SelStart = lInizioTemp - 1
.SelLength = lFineTemp - lInizioTemp + 1
End If
Else

'cifra o testo iniziale non trovati
MsgBox "Testo non trovato", vbOKOnly + vbExclamation, App.Title
End If
Loop While
(lFine = 0) And (lInizio < Len(.Text))

End With

cmdTrova.Enabled = True
cmdChiudi.Enabled = True
Me.MousePointer = vbDefault

txtTrova.SetFocus

End Sub


Restano ancora da definire un paio di dettagli: sfruttare gli optionbutton OptSu, OptGiu, OptTutto, e permettere la ricerca dei caratteri usati come jolly; intendo dire proprio i caratteri "#", "?" e "*", e non il testo che essi, in quanto caratteri jolly, rappresentano.
Se l'utente, specificando ad es. "pippo*", volesse cercare proprio "pippo*" e non "pippo" seguito da un qualunque numero di caratteri? La nostra routine non glielo consentirebbe. Nella prossima lezione vedremo come risolvere il problema.