Access

  MS Access 2010+  |  Przetwarzanie tekstu  |   VBA 7.0



• Przetwarzanie teksu

Co to jest format Unicode.

Znak Informacja dodatkowa What is Unicode?

Unicode provides a unique number for every character,
no matter what the platform,
no matter what the program,
no matter what the language.

The Unicode Consortium                    

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.

iZnakiZnakiZnakiZnakiZnakiZnakiZnakiZnak
128138Š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.

iZnakiZnakiZnakiZnakiZnakiZnakiZnakiZnak
130132133134135137139145
146147148149150151153155
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ą funkcję API IsTextUnicode(...) 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