Czasami potrzebujemy przekonwertować ciąg znaków na zapis heksadecymalny. Zrobić taką konwersję możemy na dziesiątki sposobów. Podstawowe czynności to pobranie kolejnych (pojedynczych) znaków konwertowanego ciągu, odczytanie dla każdego znaku kodu ANSI w reprezentacji dziesiętnej, a następnie przekonwertowanie wartości dziesiętnej kodu ANSI na postać heksadecymalną. Podczas konwersji na postać heksadecymalną należy zadbać, by wartości liczbowe mniejsze od 16 dla których zapis heksadecymalny ma postać (&H0 = 0 do &HF = F) zapisać w postaci dwuznakowej (&H0=00 do &HF=0F), by można było jednoznacznie dokonać konwersji w kierunku przeciwnym tj. z zapisu heksadecymalnego na zapis dziesiętny.
- Aby przekonwertować ciąg znaków (jego poszczególne znaki ) na zapis heksadecymalny posłużymy się funkcjami:
• Asc(ciąg) - zwracającą wartość typu Integer odpowiadającą kodowi znaku pierwszego elementu w ciągu znaków ciąg
• Hex(liczba)- zwracającą wartość typu String reprezentującą heksadecymalną (szesnastkową) wartość argumentu liczba
• StrConv(ciąg, konwersja)- zwracającą wartość typu Variant podtyp String w postaci ciągu znaków poddanych konwersji określonej przez argument konwersja
• Mid(ciąg, start[, długość])- zwracającą wartość typu Variant podtyp String zawierającą podaną liczbę znaków długość z ciągu znaków, począwszy od pozycji start.
• Right(ciąg, długość)- zwracającą wartość typu Variant podtyp String zawierającą podaną liczbę znaków długość począwszy od prawej strony ciągu znaków.
• Format(wyrażenie[, format[, pierwszy_dzień_tygodnia [, pierwszy_tydzień_roku]]])- zwracającą wartość typu Variant podtyp String zawierającą wyrażenie sformatowane zgodnie z instrukcjami zawartymi w wyrażeniu formatującym.
• String(liczba, znak)- zwracającą wartość typu Variant podtyp String zawierającą ciąg składający się ze znaku powtórzonego podaną liczbę razy
- oraz instrukcją Mid(...)
• Mid(zmienna_znakowa, początek[, długość]) = ciąg - zastępującą podaną liczbę znaków w argumencie zmienna_znakowa typu Variant podtyp String znakami z innego ciągu znaków. Liczba zastępowanych znaków jest zawsze mniejsza lub równa liczbie znaków w zmiennej_znakowej
Wykorzystując wyżej wymienione funkcję przedstawię trzy wersje funkcji konwertujących ciąg znaków na zapis heksadecymalny.
- 1. Funkcja
TextToHexMid(ByRef sText As String) As String - Dla każdego kolejnego znaku ciągu wejściowego, zwróconego przez funkcję
Mid$, pobierany jest jego kod ANSI za pomocą funkcjiAsc, który konwertowany jest do postaci heksadecymalnej. Następnie z przodu dopisywany jest znak "0" i z tak powstałego ciągu za pomocą funkcjiRight$pobierane są dwa ostatnie znaki.
Public Function TextToHexMid(ByRef sText As String) As String
Dim i As Long
For i = 1 To Len(sText)
TextToHexMid = TextToHexMid & Right$("0" & Hex$(Asc(Mid$(sText, i, 1))), 2)
Next
End Function
- 2. Funkcja
TextToHexFormat(ByRef sText As String) As String - Ciąg wejściowy konwertowany jest za pomocą funkcji
StrConvdo tablicy bajtów. Każdy element tablicy (kod ANSI) konwertowany jest do postaci heksadecymalnej i formatowany za pomocą funkcjiFormat$do postaci dwuznakowej.
Public Function TextToHexFormat(ByRef sText As String) As String
Dim aBytes() As Byte
Dim i As Long
aBytes = StrConv(sText, vbFromUnicode)
For i = LBound(aBytes) To UBound(aBytes)
TextToHexFormat = TextToHexFormat & Format$(Hex$(aBytes(i)), "00")
Next i
End Function
- 3. Funkcja
TextToHex(ByRef sText As String) As String -
Ciąg wejściowy konwertowany jest za pomocą funkcji
StrConvdo tablicy bajtów. Przygotowywany jest bufor wyjściowy dwukrotnie dłuższy od ciągu wejściowego. Każdy element tablicy (kod ANSI) konwertowany jest do postaci heksadecymalnej i dopisywany za pomocą instrukcjiMid$na kolejnych miejscach w buforze wyjściowym.
Option Compare Database
Option Explicit
' • Function TextToHex(ByRef sText As String) As String
' Funkcja konwertująca ciąg znaków na na postać heksadecymalną
' --------------------------------------------------------------------------------------
' autor: Zbigniew Bratko - 04.2016
'
' Pobiera:
' • sText - ciąg wejściowy, który ma zostać poddany konwersji.
' Zwraca:
' Przy powodzeniu zwraca ciąg znaków przekonwertowany do postaci heksadecymalnej.
' Każdy znak ciągu wejściowego [sText] zapisany jest za pomocą dwóch znaków. Dla znaków,
' których kod ANSI jest mniejszy od 16, heksadecymalny zapis poprzedzony jest cyfrą "0" (ZERO)
' Przy niepowodzeniu zwraca ciąg zerowej długości.
' --------------------------------------------------------------------------------------
' Ciąg wejściowy konwertowany jest za pomocą funkcji StrConv do tablicy bajtów.
' Przygotowywany jest bufor wyjściowy dwukrotnie dłuższy od ciągu wejściowego.
' Każdy element tablicy (kod ANSI) konwertowany jest do postaci heksadecymalnej
' i dopisywany za pomocą instrukcji Mid$ na kolejnych miejscach w buforze wyjściowym.
Public Function TextToHex(ByRef sText As String) As String
Dim aBytes() As Byte
Dim bAsc As Byte
Dim lLen As Long
Dim i As Long
lLen = Len(sText)
' zamienia ciąg z postaci Unicode na znaki z domyślnej strony kodowej systemu (ANSI)
aBytes = StrConv(sText, vbFromUnicode)
' przygotuj bufor wyjściowy (2x dłuższy)
TextToHex = String(2 * lLen, vbNullChar)
' konwertuj poszczególne bajty do postaci heksadecymalnej
For i = 0 To lLen - 1
bAsc = aBytes(i)
If bAsc > &HF Then
Mid$(TextToHex, 2 * i + 1, 2) = Hex$(bAsc)
Else
Mid$(TextToHex, 2 * i + 1, 2) = "0" & Hex$(bAsc)
End If
Next
End Function
Prawie wszystko już wiemy na temat konwersji ciągu znaków na postać heksadecymalną. Piszę prawie ponieważ pozostało tylko przetestować szybkość działania wyżej przedstawionych funkcji.
- Test będzie się składał z dwóch zadań:
- • ciąg znaków "Ala ma Asa a Ola" (o długości 16 znaków) będzie 1000 razy konwertowany na postać heksadecymalną,
- • ciąg znaków o długości 131 072 znaków będzie jednokrotnie poddany konwersji na postać heksadecymalną
Option Compare Database
Option Explicit
#If VBA7 Then
Private Declare PtrSafe Function timeGetTime Lib "winmm.dll" () As Long
#Else
Private Declare Function timeGetTime Lib "winmm.dll" () As Long
#End If
Public Function SpeedTextToHex()
Dim sText As String
Dim sRet As String
Dim lTime As Long
Dim i As Long
Const cMyText As String = "Ala ma Asa a Ola"
Const cForTo As Long = 1000
' rozruch
sText = cMyText
lTime = timeGetTime
For i = 1 To cForTo
DoEvents
Next
lTime = timeGetTime - lTime
Debug.Print String(45, "-")
Debug.Print "Ilość wywołań = " & cForTo, "Len(sText) = " & Len(sText)
Debug.Print String(45, "-")
' wywołuj poszczególne funkcje 1000 razy dla ciągu o długości Len(sText) = 16 znaków
sRet = ""
lTime = timeGetTime
For i = 1 To cForTo
sRet = TextToHexFormat(sText)
Next
Debug.Print "TextToHexFormat", (timeGetTime - lTime); "milisekund"
sRet = ""
lTime = timeGetTime
For i = 1 To cForTo
sRet = TextToHexMid(sText)
Next
Debug.Print "TextToHexMid", , (timeGetTime - lTime); "milisekund"
sRet = ""
lTime = timeGetTime
For i = 1 To cForTo
sRet = TextToHex(sText)
Next
Debug.Print "TextToHex", , (timeGetTime - lTime); "milisekund"
'=================================================================
' utwórz ciąg znaków o długości 131 072 znaków
sText = cMyText
For i = 1 To 13
sText = sText & sText
Next
Debug.Print String(45, "-")
Debug.Print "Ilość wywołań = 1", "Len(sText) = " & Len(sText)
Debug.Print String(45, "-")
' wywołaj poszczególne funkcje dla ciągu o długości Len(sText) = 131 072 znaków
sRet = ""
lTime = timeGetTime
sRet = TextToHexFormat(sText)
Debug.Print "TextToHexFormat", (timeGetTime - lTime); "milisekund"
sRet = ""
lTime = timeGetTime
sRet = TextToHexMid(sText)
Debug.Print "TextToHexMid", , (timeGetTime - lTime); "milisekund"
sRet = ""
lTime = timeGetTime
sRet = TextToHex(sText)
Debug.Print "TextToHex", , (timeGetTime - lTime); "milisekund"
End Function
Szybkość funkcji konwertującej krótki tekst jest bez znaczenia. Czy to będą 3/100 sekundy, czy 8/1000 lub 3/1000 sekundy dla pojedynczej operacji konwersji,
praktycznie nie jesteśmy w stanie stwierdzić, która funkcja wykonuje się najdłużej. Różnice szybkości będą zauważalne dla bardzo dużej ilości operacji (rzędu 100 000 lub więcej). Dla krótkich tekstów
funkcja TextToHex(...) jest ok. 3 razy szybsza od funkcji TextToHexMid(...) oraz 10 razy szybsza od funkcji TextToHexFormat(...)
Inaczej sprawa wygląda dla bardzo długich ciągów znaków. Przykładowo dla ciągu o długości 130 000 znaków obie funkcje:
TextToHexMid(...) oraz TextToHexFormat(...) są przeraźliwie wolne w porównaniu z funkcją TextToHex(...),
która jest ok. 400 x szybsza od obu funkcji.
