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
StrConv
do 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
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ą 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.
Brak komentarzy:
Prześlij komentarz