Apostrof

Als je met VBA werkt moet je vaak commando's opbouwen die uit een vast en een variabel deel bestaan. Dat is bijvoorbeeld het geval als je een criterium opbouwt waarbij de criteriumwaarde in een formulierveld staat. Als de criteriumwaarde een tekstveld is, moet je om de waarde bovendien aanhalingstekens plaatsen. Omdat je om de vaste delen van het ctriterium al dubbele aanhalingstekens zet, zet je rond de tekstwaarde enkele aanhalingstekens. Zo'n criterium zie er dan zo uit:
"Identificatie = '" & Me.Keuzelijst & "'"

Dit gaat goed zolang er in de tekstwaarde zelf niet een apstrof (= enkel aanhalingsteken) voorkomt. Is dat wel het geval (zoals in de tekstwaarde 's Gravenhage), dan raakt Access de draad kwijt.

Een oplossing voor dit probleem is om afhankelijk van de vraag of er al dan niet apostrofs voorkomen in de tekstwaarde, er dubbele danwel enkele aanhalingstekens omheen te plaatsen. Je stuit dan nog wel op een opbouwprobleem als je dubbele aanhalingstekens rond een tekstwaarde (met apostrof) nodig hebt. De volgende varianten werken namelijk niet:
"Identificatie = " & """ & Me.Keuzelijst & """
"Identificatie = " & '"' & Me.Keuzelijst & '"'
'Identificatie = ' & '"' & Me.Keuzelijst & '"'

Dat kunnen we dan weer oplossen door in plaats van een dubbel aanhalingsteken in te tikken, met de functie Chr de tekenwaarde van het dubbele aanhalingsteken (34) op te geven. Een stukje code om naar een bepaald record te navigeren zou er dan zo uit kunnen zien:
Sub Keuzelijst_AfterUpdate()
If InStr(Me.Keuzelijst, "'") > 0 Then
    Me.RecordsetClone.FindFirst "Identificatie =" & Chr(34) & Me.Keuzelijst & Chr(34)
Else
    Me.RecordsetClone.FindFirst "Identificatie ='" & Me.Keuzelijst & "'"
End If

Me.Bookmark = Me.RecordsetClone.Bookmark
End Sub

Met behulp van de functie Instr bepalen we eerst of er in de tekstwaarde apostrofs voorkomen. Als dat het geval is bouwen we een criterium op met dubbele aanhalingstekens rond de tekstwaarde. Zo niet, dan kunnen we op de klassieke manier opbouwen met enkele aanhalingstekens.

Deze oplossing zal in veel gevallen werken. Wanneer je de situatie hebt dat er in een en dezelfde tekstwaarde zowel apostrofs als dubbele aanhalingstekens kunnen staan, faalt deze echter jammerlijk. Als we op de beschreven manier vaststellen dat er apostrofs in de tekstwaarde voorkomen, gaan we er dubbele aanhalingstekens omheen zetten. Maar omdat die in de tekstwaarde zelf ook voorkomen schiet Access in de stress. Hier zijn dus drastischer maatregelen nodig.
Wat we in zo'n geval doen is de tekstwaarde in twee of meer delen opknippen. Dat doen we zo dat in elk deel hooguit één apostrof of één dubbel aanhalingsteken voorkomt.
Een tekstwaarde als:
dit is 'r een "voorbeeld" van
knippen we op tot:
dit is '
r een "
voorbeeld"
 van

Elk van deze delen kunnen we omhullen met de juiste aanhalingstekens. Voorzien van aanhalingstekens plakken we de delen aan elkaar en bieden die string aan als criterium. In het voorbeeld ziet de string er zo uit:
"dit is '" & 'r een "' & 'voorbeeld"' & " van"

Dit kunstje van opknippen en aan elkaar plakken heb ik in een functie gegoten die er zo uit ziet:
Function ZoekString(InVeld As String) As Variant
Dim evEnkel As Byte
Dim evDubbel As Byte
Dim StartPos As Byte
Dim Stukje As String
Dim Geheel As String

evEnkel = InStr(InVeld, Chr(39))
evDubbel = InStr(InVeld, Chr(34))

If evEnkel = 0 And evDubbel = 0 Then
    ZoekString = Chr(34) & InVeld & Chr(34)
    Exit Function
End If

Geheel = ""
StartPos = 1

Herhaal:
If evEnkel <> 0 And evDubbel <> 0 Then
    If evEnkel < evDubbel Then
        Stukje = Chr(34) & Mid(InVeld, StartPos, evEnkel - StartPos + 1) & Chr(34) & " & "
        StartPos = evEnkel + 1
        Geheel = Geheel & Stukje
    Else
        Stukje = Chr(39) & Mid(InVeld, StartPos, evDubbel - StartPos + 1) & Chr(39) & " & "
        StartPos = evDubbel + 1
        Geheel = Geheel & Stukje
    End If
Else
    If evEnkel <> 0 Then
        Stukje = Chr(34) & Mid(InVeld, StartPos, evEnkel - StartPos + 1) & Chr(34) & " & "
        StartPos = evEnkel + 1
        Geheel = Geheel & Stukje
    Else
        If evDubbel <> 0 Then
            Stukje = Chr(39) & Mid(InVeld, StartPos, evDubbel - StartPos + 1) & Chr(39) & " & "
            StartPos = evDubbel + 1
            Geheel = Geheel & Stukje
        Else
            Stukje = Chr(34) & Mid(InVeld, StartPos, Len(InVeld) - StartPos + 1) & Chr(34) & " & "
            StartPos = Len(InVeld) + 1
            Geheel = Geheel & Stukje
        End If
    End If
End If

If StartPos <= Len(InVeld) Then
    evEnkel = InStr(StartPos, InVeld, Chr(39))
    evDubbel = InStr(StartPos, InVeld, Chr(34))
    GoTo Herhaal
End If

ZoekString = Left(Geheel, Len(Geheel) - 3)
End Function

De functie bepaalt telkens de positie van het eerstvolgende (ev) enkele (tekenwaarde 39) of dubbele aanhalingsteken (tekenwaarde 34). Zodra die positie bepaald is maakt hij een stukje tekst dat begint op de positie waar hij begon te zoeken en eindigt met het aanhalingsteken. Om de tekst worden de toepasselijke aanhalingstekens geplaatst en de functie zet er een & achter. Het stukje wordt geplakt achter eventueel eerder gemaakte stukjes. De volgende zoekslag begint 1 positie na het laatstgevonden aanhalingsteken.

Toegepast op het eerder gegeven voorbeeld van navigeren naar een bepaald record, gebruiken we deze functie als volgt:
Sub Keuzelijst_AfterUpdate()
Me.RecordsetClone.FindFirst "Identificatie = " & ZoekString(Me.Keuzelijst)
Me.Bookmark = Me.RecordsetClone.Bookmark
End Sub

Klik hier om de voorbeelddatabase te downloaden.