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 27

Questa lezione, consultata da 16522 utenti, è stata giudicata di ottimi contenuti , con un'esposizione perfettamente comprensibile e con un livello di approfondimento ottimo da 36 votanti.


Lezione 27

L'ultima lezione si era conclusa con alcuni dettagli da definire a proposito della ricerca di testo: ad es. occorre tener conto della direzione di ricerca scelta dall'utente.
Per fare ciò dobbiamo introdurre un'altra variabile che ci indichi la direzione: risulta comodo che questa variabile sia di tipo numerico e che abbia valore +1/-1 a seconda che la direzione di ricerca sia verso il basso o verso l'alto.
Questo perché per cercare un testo verso il basso ci è venuto naturale incrementare un contatore che indichi la posizione corrente all'interno del testo; analogamente, per cercare un testo verso l'alto sarà sufficiente decrementare quel contatore, senza modificare pesantemente l'algoritmo di ricerca.
Il flag di direzione può essere impostato in questo modo:

lDirezione = IIf(optSu.Value = True, -1, 1)

Se la direzione scelta dall'utente è verso l'alto, il flag assume valore -1, in modo che l'incremento del contatore può essere modificato semplicemente passando da un loop del tipo:

'cerca la prima cifra
Do
lInizio = lInizio + 1
Loop Until (Mid$(.Text, lInizio, 1) Like "#") Or (lInizio > Len(.Text))

A uno del tipo:

'cerca la prima cifra
Do
lInizio = lInizio + 1 * lDirezione
Loop Until (Mid$(.Text, lInizio, 1) Like "#") Or (lInizio > Len(.Text)) Or (lInizio < 1)


Come si diceva, se la direzione scelta è verso l'alto il flag lDirezione sarà -1 e quindi il contatore (in questo caso lInizio) sarà decrementato anziché incrementato.
Se la direzione scelta è "tutto", siamo in una situazione analoga alla direzione "giù", solo che bisognerà cercare dall'inizio anche se il cursore si trova a metà del testo:


If optTutto.Value Then
lInizio = 0
Else
lInizio = .SelStart + .SelLength
End If


Quando invece il testo è cercato non incrementando un contatore ma usando la funzione InStr, nel caso di ricerca verso l'alto basterà utilizzare la funzione InStrRev:

'cerca il testo puro iniziale
If lDirezione = 1 Then
lInizio = InStr(lInizio + 1, .Text, sTestoPuro(0), lTipoRicerca)
Else
lInizio = InStrRev(.Text, sTestoPuro(0), lInizio, lTipoRicerca)
End If


Dobbiamo però ricordare che, se il testo va cercato verso l'alto, non va bene impostare il punto di partenza aggiungendo SelLength a SelStart, perché dovendo cercare "all'indietro" continueremmo a trovare sempre lo stesso testo: infatti il punto di partenza della ricerca sarebbe successivo al testo da cercare.
Quando il testo andava cercato verso il basso, dovevamo impostare il punto di partenza a una posizione successiva a SelStart; se il testo va cercato verso l'alto, il punto di partenza deve precedere SelStart.
Pertanto possiamo scrivere:


If optSu.Value Then
lDirezione = -1
lInizio = .SelStart
Else
lDirezione = 1
If optGiu.Value Then
lInizio = .SelStart + .SelLength
Else 'optTutto
lInizio = 0
End If
End If


In questa If abbiamo distinto i tre casi (direzione su, giù, tutto), e nel caso in cui la direzione scelta sia "tutto" abbiamo impostato a zero la variabile lInizio; questo perché, come si è detto prima, la ricerca deve coinvolgere tutto il testo del file, indipendentemente da dove si trova il cursore.
Tuttavia, ciò è vero solo quando si procede alla prima ricerca del testo: quando si cerca l'occorrenza successiva sarebbe sbagliato impostare di nuovo a zero il punto di partenza, altrimenti la routine continuerebbe a trovare sempre lo stesso testo (la prima occorrenza dall'inizio del file).
Si potrebbe usare un flag per indicare se la ricerca su "tutto" il file è all'inizio o sta continuando, tuttavia in questo caso potrebbe risultare comodo sfruttare l'evento Click dell'OptionButton in questo modo:


Private Sub optTutto_Click()
frmNotePad.txtFile.SelStart = 0
End Sub

Quando l'utente seleziona la direzione di ricerca "tutto", il cursore viene automaticamente impostato all'inizio del file: pertanto non c'è più bisogno dell'istruzione lInizio=0 nella routine di ricerca:

If optSu.Value Then
lDirezione = -1
lInizio = .SelStart
Else
lDirezione = 1
lInizio = .SelStart + .SelLength
End If

Così, con qualche piccola modifica, abbiamo implementato la ricerca in tutte le direzioni. Resta da trattare il caso della ricerca dei caratteri jolly.
Per permettere all'utente di cercare uno dei caratteri utilizzati come jolly (*, ?, #) occorre far capire alla routine di ricerca che il carattere inserito va preso come tale e non come simbolo che rappresenta un set di caratteri.
La tecnica tradizionale per ottenere questo scopo è quella di abilitare una "sequenza di escape": le sequenze escape sono sequenze di caratteri che attribuiscono ai caratteri successivi un significato differente da quello normale.
Ad es., un problema comune che si incontra in Visual Basic è quello di assegnare a una variabile stringa una stringa comprensiva di virgolette; se io scrivo:


sStringa="ciao"

la variabile sStringa conterrà le lettere "c", "i", "a", "o", ma non le virgolette che racchiudono queste lettere: questo perché le virgolette in Visual Basic (come in altri linguaggi) identificano proprio le stringhe; se non usassimo le virgolette, Visual Basic penserebbe che "ciao" è il nome di una variabile o una funzione o un'istruzione.
Ma se io volessi assegnare a sStringa la parola "ciao" CON le virgolette, come potrei fare?
Un modo è quello di concatenare le stringhe utilizzando il codice ascii delle virgolette:


sStringa=chr$(34) & "ciao" & chr$(34)

Ma un altro modo è quello di usare le virgolette in un modo particolare, ovvero:

sStringa="""ciao"""

Ogni sequenza di tre virgolette rappresenta… le virgolette ripetute una sola volta.
Ripeterle solo due volte non basterebbe, perché sarebbero confuse con la stringa nulla "", perciò occorre ripeterle tre volte: è come se le prime virgolette rappresentassero l'inizio della stringa, e le seconde virgolette fossero un modo per dire: "guarda che il carattere successivo (cioè le terze virgolette) vanno intese come testo, e non come carattere di chiusura della stringa"; lo stesso vale per le tre virgolette finali. In altre parole, in questo contesto le virgolette vengono usate come sequenza di escape, che alterano il normale significato attribuito alle virgolette.
Un problema analogo si incontra nel linguaggio C quando occorre specificare il carattere "\" come testo: infatti questo carattere è solitamente utilizzato come carattere di escape per rappresentare particolari sequenze di caratteri.
Tornando a noi, dobbiamo inventarci un carattere di escape che inibisca l'uso dei caratteri jolly; supponiamo di usare proprio il backslash "\" come carattere di escape: il testo "pippo*" significa come al solito "pippo" seguito da qualunque cosa, ma "pippo\*" significa semplicemente "pippo*", dove l'asterisco questa volta non è un carattere jolly ma è un carattere come gli altri.
Tenete presente che si potrebbe utilizzare il carattere di escape anche per altri scopi, ad es. per indicare il ritorno a capo: potremmo decidere cioè che la sequenza "\a" indichi il ritorno a capo, quindi: "pippo\apiero" non sarebbe altro che:


"pippo
piero"

Questa è una soluzione che risulta comoda data la difficoltà di rappresentare certi caratteri su una sola riga o perché il tasto corrispondente ("invio" nel caso del ritorno a capo) è associato ad altre funzioni, ad es. alla pressione di un pulsante.
Ad ogni modo, per ora limitiamoci ai caratteri jolly.
Ripercorriamo l'analisi della stringa immessa dall'utente nel campo "trova": dapprima si cercano (per eliminarli) gli asterischi iniziali e finali; prima di eliminare gli asterischi finali, però occorre controllare che non siano preceduti dal carattere escape "\":


lFine = Len(txtTrova.Text)
Do While Mid$(txtTrova.Text, lFine, 1) = "*"
lFine = lFine - 1
Loop
If
Mid$(txtTrova.Text, lFine, 1) = "\" Then 'carattere escape
lFine = lFine + 1
End If
txtTrova.Text = Mid$(txtTrova.Text, lInizio, lFine - lInizio + 1)

Il puntatore lFine viene spostato in avanti per non perdere l'ultimo asterisco.
L'analisi prosegue poi cercando i testi puri e verificando se sono preceduti o seguiti da una cifra o da un carattere: nel caso in cui siano presenti caratteri escape, la routine confonderebbe il carattere "\" con un carattere qualunque, "distorcendo" la ricerca dei "veri" testi puri; ad es., se la stringa cercata dall'utente fosse: "*\#pippo*\?piero" i testi puri trovati sarebbero "\" e "piero" anziché "#pippo" e "?piero".
In teoria dovremmo "aggiustare" la stringa da cercare in modo che la routine estragga correttamente i testi puri, ma in realtà sembra più conveniente lasciare l'aggiustamento a quando i testi puri sono già stati estratti: tutto quello che occorre fare è sostituire i caratteri escape con il carattere successivo:


If Right(sTestoPuro(0), 1) = "\" Then
Mid$(sTestoPuro(0), Len(sTestoPuro(0)), 1) = Mid$(txtTrova.Text, _
InStr(1, txtTrova.Text, sTestoPuro(0)) + Len(sTestoPuro(0)), 1)
End If
If
Right(sTestoPuro(1), 1) = "\" Then
Mid$(sTestoPuro(1), Len(sTestoPuro(1)), 1) = Mid$(txtTrova.Text, _
InStr(1, txtTrova.Text, sTestoPuro(1)) + Len(sTestoPuro(1)), 1)
End If

Inoltre, bisogna reimpostare l'elemento 1 dei vettori lCifra e lCarattere, perché se l'ultimo testo puro contiene un carattere escape significa che un "?" o un "#" sono stati erroneamente interpretati come caratteri jolly:

If Right(sTestoPuro(1), 1) = "\" Then
Mid$(sTestoPuro(1), Len(sTestoPuro(1)), 1) = Mid$(txtTrova.Text, _
InStr(1, txtTrova.Text, sTestoPuro(1)) + Len(sTestoPuro(1)), 1)
If Right$(sTestoPuro(1), 1) = "#" Then
lCifra(1) = lCifra(1) - 1
ElseIf Right$(sTestoPuro(1), 1) = "?" Then
lCarattere(1) = lCarattere(1) - 1
End If
End If

Prima di iniziare la ricerca occorre infine modificare opportunamente il contenuto del campo trova, poiché è quello che, tramite l'operatore Like, determina se il testo trovato corrisponde effettivamente al testo da cercare:

txtTrova.Text = Replace(txtTrova.Text, "\*", "[*]")
txtTrova.Text = Replace(txtTrova.Text, "\#", "[#]")
txtTrova.Text = Replace(txtTrova.Text, "\?", "[?]")

L'uso delle parentesi quadre permette all'operatore Like di considerare i caratteri "jolly" come caratteri normali; le parentesi quadre rappresentano quindi una sorta di sequenza escape per l'operatore Like.
Occorre anche salvare la stringa di ricerca inserita dall'utente per evitare che nel campo "trova" restino le modifiche appena fatte: utilizziamo allo scopo una variabile sTestoCercato.

La nostra routine di ricerca è quindi diventata:


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 lDirezione As Long
Dim sTestoPuro(1) As String
Dim sTestoTrovato As String
Dim sTestoCercato As String
lInizio = 0: lFine = 0
Erase sTestoPuro
Erase lCifra

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

sTestoCercato = txtTrova.Text

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
If
Mid$(txtTrova.Text, lFine, 1) = "\" Then 'carattere escape
lFine = lFine + 1
End If
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)
'If Mid$(txtTrova.Text, lFine - 1, 1) = "\" Then
' Mid$(txtTrova.Text, lFine - 1, 1) = Mid$(txtTrova.Text, lFine, 1)
'End If

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 Right(sTestoPuro(0), 1) = "\" Then
Mid$(sTestoPuro(0), Len(sTestoPuro(0)), 1) = Mid$(txtTrova.Text, _
InStr(1, txtTrova.Text, sTestoPuro(0)) + Len(sTestoPuro(0)), 1)
End If
If Right(sTestoPuro(1), 1) = "\" Then
Mid$(sTestoPuro(1), Len(sTestoPuro(1)), 1) = Mid$(txtTrova.Text, _
InStrRev(txtTrova.Text, sTestoPuro(1)) + Len(sTestoPuro(1)), 1)
If Right$(sTestoPuro(1), 1) = "#" Then
lCifra(1) = lCifra(1) - 1
ElseIf Right$(sTestoPuro(1), 1) = "?" Then
lCarattere(1) = lCarattere(1) - 1
End If
End If

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

txtTrova.Text = Replace(txtTrova.Text, "\*", "[*]")
txtTrova.Text = Replace(txtTrova.Text, "\#", "[#]")
txtTrova.Text = Replace(txtTrova.Text, "\?", "[?]")

With frmNotePad.txtFile
If optSu.Value Then
lDirezione = -1
lInizio = .SelStart
Else
lDirezione = 1
lInizio = .SelStart + .SelLength
End If
lFine = 0
lTipoRicerca = IIf(chkCaseSens.Value = vbChecked, vbBinaryCompare, vbTextCompare)
Do
If lCifra(0) >= 0 Then

'cerca la prima cifra
Do
lInizio = lInizio + 1 * lDirezione
Loop Until (Mid$(.Text, lInizio, 1) Like "#") Or (lInizio > Len(.Text)) Or (lInizio < 1)
If lInizio > Len(.Text) Then
lInizio = 0
Else
lFine = lInizio
End If
Else

If Len(sTestoPuro(0)) Then
'cerca il testo puro iniziale
If lDirezione = 1 Then
lInizio = InStr(lInizio + 1, .Text, sTestoPuro(0), lTipoRicerca)
Else
lInizio = InStrRev(.Text, sTestoPuro(0), lInizio, lTipoRicerca)
End If
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)) Or (lFine < 1)
If lFine > Len(.Text) Then lFine = 0
Else
lFine = lFine + 1
'cerca il testo puro finale
If Len(sTestoPuro(1)) Then
lFine = InStr(lFine + 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)) And (lInizio > 0)

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

txtTrova.Text = sTestoCercato
If frmTrova.Visible Then
txtTrova.SetFocus
End If

End Sub


Per le prove che mi è stato possibile fare, sembra che la routine funzioni a dovere.
Naturalmente è possibile tutto un lavoro di ottimizzazione e di "ripulitura" del codice per renderlo più snello ed efficiente, ma per ora mi fermo qua.