Jak sprawdzić, czy tekst jest w formacie Unicode.
Aby ustrzec się przed nieprawidłowym działaniem funkcji operujących na ciągach znaków w formacie Unicode, powinniśmy
napisać funkcję sprawdzającą format tekstu, przed przekazaniem go do funkcji operujących na tekście w formacie Unicode.
Windows API, w bibliotece "advapi32", zawiera funkcję
IsTextUnicode(...) służącą do testowania tekstu roboczego,
w oparciu o którą spróbuję napisać funkcję sprawdzającą format wejściowego ciągu znaków.
Przykładowo. Poniższa deklaracja funkcji API IsTextUnicode(...) Lib "kernel32" Alias "FindFirstFileW" oznacza, że funkcja pobiera i zwraca ciągi znaków w formacie Unicode. Określa to Alias z literą W na końcu Aliasu. który pochodzi od pierwszej litery słowa ("Wide").
Private Declare Function FindFirstFile Lib "kernel32" _ Alias "FindFirstFileW" _ (ByVal lpFileName As String, _ lpFindFileData As WIN32_FIND_DATA) As Long
Aby sprawdzić, czy przekazany argument lpFileName (pełna ścieżka do pliku lub folderu) jest w formacie Unicode
możemy użyć funkcji IsTextUnicode(...).
Generalnie chodzi o rozpoznanie, czy znak(i) Asterisk "*" oraz
znak(i) QuestionMark "?" stosowane w maskach wyszukiwania, są w formacie Unicode.
Jednoznakowe ciągi w formacie Unicode
Sprawdźmy, jak sprawuje się funkcja IsTextUnicode(...) dla jednoznakowych ciągów przekonwertowanych na format Unicode. Po pierwszych testach lepiej jest przedstawić które znaki przekonwertowane na format Unicode, są przez funkcję IsTextUnicode(...) poprawnie interpretowane jako format Unicode.
Public Function tekstIsCharUnicode() As Boolean Dim sText As String Dim fRet As Boolean Dim i As Long Const IS_TEXT_UNICODE_UNICODE_MASK = &HF ' sprawdź znaki zakresu ASCII For i = 1 To 255 ' przekonwertuj znak na format Unicode sText = StrConv(Chr$(i), vbUnicode) ' sprawdź, czy znak jest w formacie Unicode fRet = CBool(IsTextUnicode(ByVal sText, Len(sText), IS_TEXT_UNICODE_UNICODE_MASK)) ' jeżeli znak jest w formacie Unicode to go drukuj If fRet Then Debug.Print i; Chr$(i) End If Next End Function
Jedynie 56 znaków z 255 jest poprawnie interpretowane przez funkcję IsTextUnicode(...) jako format Unicode.
Poniżej zestawienie pojedynczych znaków, które przeszły test z użyciem flagi:
lpiResults = IS_TEXT_UNICODE_UNICODE_MASK = &HF, która jest kombinacją kilku flag,
m.in zawiera flagę IS_TEXT_UNICODE_STATISTICS, która powoduje, że sprawdzanie tekstu jest dokonywane
przy zastosowaniu analizy statystycznej. Metoda ta nie daje stuprocentowej pewności dla krótkich ciągów znaków.
i | Znak | i | Znak | i | Znak | i | Znak | i | Znak | i | Znak | i | Znak | i | Znak |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
128 | € | 138 | Š | 140 | Ś | 141 | Ť | 142 | Ž | 143 | Ź | 154 | š | 156 | ś |
157 | ť | 158 | ž | 159 | ź | 161 | ˇ | 162 | ˘ | 163 | Ł | 165 | Ą | 170 | Ş |
175 | Ż | 178 | ˛ | 179 | ł | 185 | ą | 186 | ş | 188 | Ľ | 189 | ˝ | 190 | ľ |
191 | ż | 192 | Ŕ | 197 | Ĺ | 198 | Ć | 200 | Č | 202 | Ę | 204 | Ě | 207 | Ď |
208 | Đ | 209 | Ń | 210 | Ň | 213 | Ő | 216 | Ř | 217 | Ů | 219 | Ű | 222 | Ţ |
224 | ŕ | 229 | ĺ | 230 | ć | 232 | č | 234 | ę | 236 | ě | 239 | ď | 240 | đ |
241 | ń | 242 | ň | 245 | ő | 248 | ř | 249 | ů | 251 | ű | 254 | ţ | 255 | ˙ |
Prawie 200 pojedynczych znaków przekonwertowanych na format Unicode, nie przeszło testu. Spróbujmy teraz sprawdzić znaki za pomocą funkcji IsTextUnicode(...) i w przypadku wyniku negatywnego, sprawdzić, za pomocą funkcji InStr(), czy przekonwertowany na format Unicode znak, zawiera znak vbNullChar. Obecność znaku vbNullChar może świadczyć (ale nie musi), że testowany ciąg znaków jest w formacie Unicode.
Public Function tekstIsCharUnicode() As Boolean Dim sText As String Dim fRet As Boolean Dim i As Long Const IS_TEXT_UNICODE_UNICODE_MASK = &HF ' sprawdź znaki zakresu ASCII For i = 1 To 255 ' przekonwertuj znak na format Unicode sText = StrConv(Chr$(i), vbUnicode) ' sprawdź, czy znak jest w formacie Unicode fRet = CBool(IsTextUnicode(ByVal sText, Len(sText), IS_TEXT_UNICODE_UNICODE_MASK)) ' jeżeli znak NIE jest w formacie Unicode ' jeżeli tekst NIE jest w formacie Unicode, If Not fRet Then ' to sprawdź, czy zawiera znak vbNullChar If InStr(1, sText, vbNullChar, vbBinaryCompare) = 0 Then ' jeżeli nie, to drukuj znak ASCII Debug.Print i; Chr$(i) End If End If Next End Function
Po zastosowaniu instrukcji
If InStr(1, sText, vbNullChar, vbBinaryCompare) = 0 Then
pozostało tylko 18 pojedynczych znaków, które nie zostały rozpoznane, że są w formacie Unicode.
i | Znak | i | Znak | i | Znak | i | Znak | i | Znak | i | Znak | i | Znak | i | Znak |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
130 | ‚ | 132 | „ | 133 | … | 134 | † | 135 | ‡ | 137 | ‰ | 139 | ‹ | 145 | ‘ |
146 | ’ | 147 | “ | 148 | ” | 149 | • | 150 | – | 151 | — | 153 | ™ | 155 | › |
195 | Ă | 227 | ă |
Co ciekawsze funkcja IsTextUnicode(...), która poprawnie rozpoznaje literę "Ć" w formacie Unicode,
to ciąg znaków Ƈ po przekonwertowaniu na format
Unicode = StrConv(Chr$(230) & Chr$(135), vbUnicode)
nie jest rozpoznawany jako format Unicode. Inna z kilku ciekawostek poniżej:
Zmienne sText1 i sText2 nie są rozpoznawane jako Unicode
sText1 = Chr(130) & Chr(132) & Chr(133) & Chr(134) & Chr(135) & Chr(137) & Chr(139) '& Chr(145)
sText2 = Chr(145) & Chr(146) & Chr(147) & Chr(148) & Chr(149) & Chr(150) & Chr(151) & Chr(153) & Chr(155) & Chr(227) ale dodanie na końcu zmiennej sText1 znaku Chr(145)
powoduje, że tak powstały tekst zostaje rozpoznany jako format Unicode
sText3 = sTekst1 & Chr(145)
Funkcja własna próbująca rozpoznać, czy tekst jest w formacie Unicode.
Poniższa funkcja jest niejednoznaczna. Działa z ograniczeniami opisanymi powyżej, jak również mogą „zaistnieć” inne, niespodziewane przypadki.
⊗ Public Function tekstIsUnicode(ByVal sText As String) As Boolean
- Funkcja tekstIsUnicode (...) testuje wejściowy ciąg znaków za pomocą funkcji API IsTextUnicode(...), czy jest on w formacie Unicode. Gdy wejściowy tekst nie przejdzie testu (nie jest w formacie Unicode), dodatkowo jest sprawdzana obecność znaku vbNullChar za pomocą funkcji InStr(...), obecność którego może świadczyć (ale nie musi), że testowany ciąg znaków jest w formacie Unicode.
- argumenty:
- sText
- ciąg znaków, który poddany zostanie testowi
- zwraca:
-
Zwraca True gdy tekst jest w formacie Unicode, w przeciwnym wypadku zwraca False.
- autor: Zbigniew Bratko
- data: 01.12.2017
Option Compare Database Option Explicit #If VBA7 Then Private Declare PtrSafe Function IsTextUnicode Lib "advapi32" _ (ByVal lpBuffer As String, _ ByVal iSize As Long, _ lpiResult As Long) As Long #Else Private Declare Function IsTextUnicode Lib "advapi32" _ (ByVal lpBuffer As String, _ ByVal iSize As Long, _ lpiResult As Long) As Long #End If Private Const IS_TEXT_UNICODE_NULL_BYTES = &H1000 Private Const IS_TEXT_UNICODE_STATISTICS = &H2 Private Const IS_TEXT_UNICODE_UNICODE_MASK = &HF Public Function tekstIsUnicode(ByVal sText As String) As Boolean Dim fRet As Boolean ' sprawdź, czy tekst jest w formacie Unicode fRet = CBool(IsTextUnicode(ByVal sText, Len(sText), IS_TEXT_UNICODE_STATISTICS)) ' jeżeli nie jest, to sprawdź, czy zawiera znak vbNullChar If fRet = False Then If (InStr(1, sText, vbNullChar, vbBinaryCompare)) > 0 Then fRet = True End If tekstIsUnicode = fRet End Function