Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ? (https://www.delphipraxis.net/205023-beste-ishex-achar-char-methode-um-character-auf-hex-zu-pruefen.html)

Rollo62 24. Jul 2020 11:05

Delphi-Version: 10.4 Sydney

Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Hallo zusammen,

ich baue gerade ein paar Basis-Funktionen um, und bin im Moment darüber gestolpert
das CharInSet deprecated ist.

Da frage ich mich was wohl am Besten / Schnellsten wäre um ein HEX-Char zu entdecken.
Also ich suche ein
Delphi-Quellcode:
  function IsHEX( const AChar :Char ) : Boolean;



1. Das wäre die volle Abfrage, mit Ord() als intrinsic Funktion sollte bei Konstanten doch eine Integer Konstante eintragen, oder rechnet der etwa bei Runtime Alle einzeln jedes Mal neu durch ?
Delphi-Quellcode:
var LChr : Integer;

     LChr := Ord( AChar );

     if    InRange( LChr, Ord( '0' ), Ord( '9' ) )
         or InRange( LChr, Ord( 'A' ), Ord( 'F' ) )
         or InRange( LChr, Ord( 'a' ), Ord( 'f' ) ) then
         Result := True // Is is a HEX Char
     else
         Result := False;
2. Das hier mit vorheriger Konvertierung ToUpper (wird wohl langsamer sein)
Delphi-Quellcode:
var LChr : Integer;

     LChr := Ord( AChar.ToUpper );

     if    InRange( LChr, Ord( '0' ), Ord( '9' ) )
         or InRange( LChr, Ord( 'A' ), Ord( 'F' ) ) then
         Result := True // Is is a HEX Char
     else
         Result := False;
3. Oder besser ohne vorherige Konvertierung ?
Delphi-Quellcode:
     if    ( (AChr >= '0' ) and ( AChar <= '9' ) )
         or ( (AChr >= 'A' ) and ( AChar <= 'F' ) )
         or ( (AChr >= 'a' ) and ( AChar <= 'f' ) ) then
         Result := True // Is is a HEX Char
     else
         Result := False;
4. Der Gewinner ist wohl eine Sprungtabelle, aber das kann es doch auch nicht sein ... Mal abgesehen vom Speicher.
Delphi-Quellcode:
     Result := CHEXTable( AChr and $FF );

//mal das hier als C Anregung
int isHex(char c)
{
    static int s_hex_digit[1 << CHAR_BIT] = {
        ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1,
        ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,
        ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1,
        ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1
    };
    return s_hex_digit[(unsigned char)c];
}


5. Ein HashMap ähnliches Dictionary ?


6. Eine Version irgendwas mit RexEx ( neee, das doch wohl nicht :stupid:)
Delphi-Quellcode:
  Result LRegex.IsMatch( AChar, @"\A\b[0-9a-fA-F]+\b\Z");


Oder gibt es da vielleicht doch was "Amtlich" Fertiges in Delphi ?

himitsu 24. Jul 2020 11:13

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Im Delphi gibt es mehrere Funktionen/Klassen für Base64.
Hab hier grade nur XE und ein "halbes" 10.3 drauf ... units SysUtils/EncdDecd/TypeTrans können nur umcodieren ... weiß aber nicht ob die neuen Klassen im Delphi auch eine IsBase64-Funktion drin haben.
PS: Eine der neuen Klassen erlaubt auch Leerzeichen und Zeilenumbrüche im Base64-Text, um z.B. für den REST-Server zu lange Zeilen im JSON umbrechen zu können.

Ansonsten einfach dekodieren lassen ... entweder es geht oder nicht und wenn nicht, dann war es kein Base64. :stupid:



CharInSet war ja auch die krankeste Idee, die jemand jemals hatte, dazumal sie im Inneren sowieso nur genau das Selbe machte, wie das, was man damit ersetzen sollte zwangsweise musste.

Rollo62 24. Jul 2020 11:15

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Zitat:

Zitat von himitsu (Beitrag 1470273)
Im Delphi gibt es mehrere Funktionen/Klassen für Base64.

Einfach dekodieren lassen ... entweder es geht oder nicht und wenn nicht, dann ist es kein Base64. :stupid:

Dankesehr für den Vorschlag, und das ist wirklich das schnellste ? :gruebel:
Muss ich mal reinschauen, KIJKG (*).



(*) KIJKG = Kann ich ja kaum glauben.

himitsu 24. Jul 2020 11:26

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Hatte vor Kurzem eine gefunden, aber da hier 10.3 grad kaputt und mein 10.4 daheim, bzw. der Quellcode wo ich die benutzte, grad etwas auser Reichweite ist, kann ich nicht schnell mal nachsehn.

Delphi hat inzwischen selbst viele neue Units/Klassen für Sowas, bzw. in den Basis-Units vom Indy, sowie in den HTTP/REST/SOAP/MAIL/DataSnap/EMS/...-Units, lässt sich sowas eigentlich immer irgendwo finden und oftmals auch einzeln nutzen.

Rollo62 24. Jul 2020 11:30

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Naja, ich sammle mal noch ein paar Vorschläge bis Dein 10.3 wieder läuft.
Wäre ja sicher auch für Andere spannend mal ein "amtliches" Ergebnis zu haben.

TiGü 24. Jul 2020 12:41

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Delphi-Quellcode:
program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

function IsHEX(const AChar: Char): Boolean;
begin
  case AChar of
    '0' .. '9', 'A' .. 'F', 'a' .. 'f':
      Result := True;
  else
    Result := False;
  end;
end;

begin
  try
     Writeln('0: ', IsHEX('0').ToString(TUseBoolStrs.True));
     Writeln('9: ', IsHEX('9').ToString(TUseBoolStrs.True));
     Writeln('a: ', IsHEX('a').ToString(TUseBoolStrs.True));
     Writeln('f: ', IsHEX('f').ToString(TUseBoolStrs.True));
     Writeln('A: ', IsHEX('A').ToString(TUseBoolStrs.True));
     Writeln('F: ', IsHEX('F').ToString(TUseBoolStrs.True));

     Writeln('-: ', IsHEX('-').ToString(TUseBoolStrs.True));
     Writeln('/: ', IsHEX('/').ToString(TUseBoolStrs.True));
     Writeln('g: ', IsHEX('g').ToString(TUseBoolStrs.True));
     Writeln('z: ', IsHEX('z').ToString(TUseBoolStrs.True));
     Writeln('G: ', IsHEX('G').ToString(TUseBoolStrs.True));
     Writeln('Z: ', IsHEX('Z').ToString(TUseBoolStrs.True));
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
Produziert (Win32 Debug):

Code:
Project1.dpr.11: begin
0041B050 55               push ebp
0041B051 8BEC            mov ebp,esp
0041B053 51               push ecx
0041B054 668945FE        mov [ebp-$02],ax
Project1.dpr.12: case AChar of
0041B058 668B45FE        mov ax,[ebp-$02]
0041B05C 83C0D0           add eax,-$30
0041B05F 6683E80A        sub ax,$0a
0041B063 7212             jb +18     ; $0041b077
0041B065 83C0F9           add eax,-$07
0041B068 6683E806         sub ax,$06
0041B06C 7209             jb +9      ; $0041b077
0041B06E 83C0E6           add eax,-$1a
0041B071 6683E806         sub ax,$06
0041B075 7306             jnb +6      ; $0041b07d
Project1.dpr.14: Result := True;
0041B077 C645FD01         mov byte ptr [ebp-$03],$01
0041B07B EB04             jmp +4      ; $0041b081
Project1.dpr.16: Result := False;
0041B07D C645FD00         mov byte ptr [ebp-$03],$00
Project1.dpr.18: end;
0041B081 8A45FD          mov al,[ebp-$03]
0041B084 59               pop ecx
0041B085 5D              pop ebp
0041B086 C3               ret

Rollo62 24. Jul 2020 13:06

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
@Tigü, Ja super :thumb:
Warum bin ich da nicht selber drauf gekommen (bin wahrscheinlich mit den Gedanken in anderen Projekten).

Das wäre erstmal mein Favorit, bin gespannt ob man das noch toppen kann.

mytbo 24. Jul 2020 14:26

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Hallo!

Aus der mORMot Unit SynCommons die Funktionen HexToCharValid(), HexToBin() oder für einen ganzen String IsHex().

Bis bald...
Thomas

Rollo62 24. Jul 2020 15:02

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Delphi-Quellcode:
type
  TNormTableByte = packed array[byte] of byte;

var
  /// a conversion table from hexa chars into binary data
  // - returns 255 for any character out of 0..9,A..Z,a..z range
  // - used e.g. by HexToBin() function
  // - is defined globally, since may be used from an inlined function
  ConvertHexToBin: TNormTableByte;

var B,C: PtrUInt;
    tab: {$ifdef CPUX86NOTPIC}TNormTableByte absolute ConvertHexToBin{$else}PNormTableByte{$endif};

FillcharFast(ConvertHexToBin[0],SizeOf(ConvertHexToBin),255); // all to 255
  v := 0;
  for i := ord('0') to ord('9') do begin
    ConvertHexToBin[i] := v;
    inc(v);
  end;
  for i := ord('A') to ord('F') do begin
    ConvertHexToBin[i] := v;
    ConvertHexToBin[i+(ord('a')-ord('A'))] := v;
    inc(v);
  end;


function HexToCharValid(Hex: PAnsiChar): boolean;
begin
  result := (ConvertHexToBin[Ord(Hex[0])]<=15) and
            (ConvertHexToBin[Ord(Hex[1])]<=15);
end;

Der SynCommon verfolgt wohl den Table-Ansatz, der am schnellsten sein sollte, allerdings auf Kosten von 256 Einträgen.
Die ganze SysCommon Unit ist aber extrem verwurschtelt, WYSIWYG ist da nicht unbedingt gegeben.
Nur wegen dem IsHEX würde ich mir das nicht antun, auch wenn es ansonsten hochoptimiert aussieht.

himitsu 24. Jul 2020 17:19

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Delphi-Quellcode:
ByteArray := TNetEncoding.Base64.DecodeStringToBytes(MyString);

Schade, mir war vorhin so, als wäre da auch Hexadezimal mit dabei gewesen. :oops:
OK, ist schon, aber nur indirekt im URL-Encode.

Delphi-Referenz durchsuchenTNetEncoding aus System.NetEncoding



: Delphi
BinToHex, HexToBin, IntToHex, StrToInt, Format -> System.Classes
MyInt.ToHexString und Integer.Parse/TryParse -> System.SysUtils
THash.DigestAsString -> System.Hash

: Indy
TIdEncoderBinHex4.Encode und TIdDecoderBinHex4.Decode -> IdCoderBinHex
TIdHash.HashBytesAsHex -> IdHash
BinToHexStr -> IdStrings
ToHex -> IdGlobal

: noch ein paar weitere total nutzlose Beispiele, wo sowas vorkommt
JDoubleClass.toHexString -> Androidapi.JNI.JavaTypes
ICryptographicBufferStatics.DecodeFromHexString -> Winapi.Security.Cryptography

: und für die total massoristisch Veranlagten
Hex2Bin, Hex2Dec, Hex2Oct -> c:\program files (x86)\embarcadero\studio\21.0\OCX\Servers\Excel2010.pas

TiGü 24. Jul 2020 20:22

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Himi, hast du das eigentliche Problem bzw. die Fragestellung verstanden?

himitsu 24. Jul 2020 20:56

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Es ging darum zu prüfen ob es HEX ist und mein Vorschlag war ja einfach zu konvertieren und wenn es nicht geht, dann isses das nicht.

Und um nicht alles neu entwickeln zu müssen, kann man ja auch eine der fertigen Funktionen/Klassen benutzen, falls man was findet, dass zur Aufgabe passt.
(bissl blöd ist nur, dass viele der Funktionen bei falschem Input eine Zugriffsverletzung werfen oder meistens den Fehler einfach wortlos ignorieren :wall:)

Michael II 24. Jul 2020 23:22

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Wenn du TiGüs #6 noch ein inline spendierst, dann läuft's auf meinem Uraltnotebook drei Mal schneller (100 Mio Entscheide in 203ms statt 713ms).

Delphi-Quellcode:
function IsHEX(const AChar: Char): Boolean;inline;

Stevie 25. Jul 2020 02:54

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Delphi-Quellcode:
function IsHEX(const AChar: Char): Boolean;
{$OVERFLOWCHECKS OFF}
{$B+}
var
  w1, w2: Word;
begin
  w1 := Ord(AChar) - 48;           // '0' = 48
  w2 := Word(AChar) and -33;       // kleiner Trick um aus kleinen Buchstaben große zu machen
  w2 := w2 - 65;                   // 'A' = 65
  Result := (w2 <= 5) or (w1 <= 9); // wenn zwischen 'A'..'F' oder '0'..'9'
end;
Branchloses asm:
Code:
Project26.dpr.16: w1 := Ord(AChar) - 48;
004F5874 8BD0             mov edx,eax
004F5876 6683EA30         sub dx,$30
Project26.dpr.17: w2 := w2 and -33;
004F587A 6625DFFF        and ax,$ffdf
Project26.dpr.18: w2 := w2 - 65;
004F587E 6683E841         sub ax,$41
Project26.dpr.19: Result := (w2 <= 5) or (w1 <= 9);
004F5882 6683F805         cmp ax,$05
004F5886 0F96C0           setbe al
004F5889 6683FA09         cmp dx,$09
004F588D 0F96C2           setbe dl
004F5890 0AC2             or al,dl
Project26.dpr.20: end;
004F5892 C3               ret

Rollo62 25. Jul 2020 14:56

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Hallo Stefan, genau solche Tricks meinte ich :)
Ich hatte mich dunkel daran erinnert das es da noch irgendwas mathematisches gab.
Das mit dem case ist aber auch schon weit vorne.

Gefühlt würde ich trotzdem sagen das die Sprungtabelle gewinnen könnte, zumindest bei Performance,
Aber meine Lieblingslösung ist das sicher nicht, wegen der Platzverschwendung.
Da gab es aber doch auch Tricks um nicht 256 Byte Tabellen zu verbrauchen, vielleicht in Kombination mit deiner Rechnung.

Werde das nächste Woche mal Testen.

himitsu 25. Jul 2020 15:15

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Wenn es geht (Codeoptimierung und so), dann macht CASE auch derartige Berechnungen.

Delphi-Quellcode:
case i of
  1: x := 1;
  5: x := 2;
  30: x := 3;
end;

// Pseudocode, den Delphi generieren könnte, so in etwa (die mathematik)
t := i;
dec(t); if t = 0 then begin x := 1; exit; end;
dec(t, 4); if t = 0 then begin x := 2; exit; end;
dec(t, 25); if t = 0 then begin x := 3; exit; end;

// wobei Delphi GOTOs exterm gern hat und es dann eher so aussehn könnte (im Assembler ist das DEC und CMP vom IF zusammengefasst)
t := i;
dec(t); if t = 0 then goto 1;
dec(t, 4); if t = 0 then goto 2;
dec(t, 25); if t = 0 then goto 3;
goto 4;
1: x := 1; goto 4;
2: x := 2; goto 4;
3: x := 3; //goto 4;
4:

Vom "Speicher" zur Laufzeit ist Konstante und Variable kein Unterschied.
Die Variable braucht aber anfangs bissl Zeit, zum Füllen,
und bei der Laufzeit sind es zwei Pointer ... zur Variable und von da zum Speicher, wo es bei einer echten Konstante nur ein Zeiger ist, der beim Start von Windows berehnet wird. (ReallocationTabelle, falls die EXE im RAM verschoben wurde)

PS: 256 wird nicht reichen, denn Unicode sind ja 2^16 und nicht 2^8.
Wobei man das auch auf 2^7 (ASCII) und weniger kürzen/casten könnte, wenn man vorher den Bereich prüft.
Delphi-Quellcode:
if (Ord(C) < 256) and Byte(C) ......


Statt 64KB (Boolean/Char) könnten auch 8KB (1 Bit/Char) reichen,
aber vom Tempo kommt es bestimmt mit einem LongBool am Besten, da dort die CPU optimaler drauf zugreifen kann, auf einen "Integer" im RAM.
Delphi-Quellcode:
array[0..$FFFF] of LongBool

Und ganz im Ernst, bei all dem platzverschwendenden Mist, den dir Delphi schon unterjubelt, fällt es bestimmt nicht auf, wenn man die paar 256KB als Daten in die EXE einkompiliert.
(Konstante, Ressource oder ganz böse als Assembler DB versteckt)

Stevie 25. Jul 2020 17:02

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Himi, lies mal bitte etwas über branchless programming. Quasi jedes if statement in Delphi generiert einen bedingten Sprung, und auch noch so optimierte case Anweisungen tun das. Und die sind nunmal selbst bei den Sprungvorhersagen der modernen CPUS nicht so gut, als ob man gar keinen Sprung hat.

Wenn man bis in die Haarspitzen optimierten Code möchte (und in Delphi bleiben will) und ein bisschen Ahnung von C++ und assembler hat, nimmt man sich am besten den Compiler Explorer zur Hand, schreibt seinen Code in C++ und schaut sich an, was gcc oder clang daraus generieren. Entweder übernimmt man den asm Code dann so (an die Aufrufkonvention denken bzgl Register,
Delphi-Quellcode:
__attribute__((regparm(3)))
über die Routine hilft) oder man bekommt eine Idee, wie man den code schreiben könnte, damit der Delphi Compiler etwas ähnliches ausspuckt, aber die Chance für letzteres ist eher gering (im Beispiel hier hatte es geklappt).

Und immer dran denken, ob man sich gerade mit den 97% oder den 3% beschäftigt:
"Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%." - Donald Knuth

P.S.: Ah und bevor man meint, nur weil man nen bisschen gammeliges assembler schreiben kann, was dann bestimmt rattenschnell ist - bitte https://www.agner.org/optimize/ gründlich zu Gemüte führen.

freimatz 27. Jul 2020 10:54

AW: Beste IsHEX( AChar : Char ) Methode um Character auf HEX zu prüfen ?
 
Kann ich nur unterstützen. Investiert Eure Zeit lieber damit sauberen Code zu schreiben.

Zu den Speichertabellen: Das könnte auch nach hinten losgegen, weil man damit schneller den Cache füllt und so früher zum Nachladen zwingt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:03 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz