Seite 1 von 3

Gültigen VariablenNamen erkennen.

Verfasst: 30.09.2008 16:17
von cxAlex
Servus zusammen.

Ich sucher derzeit nach einer Funktion mit der man schnell erkennen kann ob eine Variable C/PB - Konform ist. d.h. sie darf aus a-z,A-Z,0-9 und _ bestehen und nicht mit einer Zahl beginnen. Die Länge des Namens spielt keine Rolle und wir nehmen auch einmal an das sie kein Pointer ist (kein *).

Ich hab bereits eine, meiner Meinung nach, schnelle Funktion geschrieben.
Nun frage ich ich mich: Geht es noch schneller? Ich wüsste keine schnellere Methode ausser vielleicht in Assembler, aber dazu reichen meine Kentnisse nicht aus. Die Funktion ist zeitkritisch, kann sein das sie einige millionen mal aufgerufen werden muss.

Hier ist mein Code, vielleich kann ihn noch jemand optimieren:

Code: Alles auswählen

Macro isValidChar(_Char)
  ; Gültige Zeichen
  ((_Char<58) And (_Char>47)) Or ((_Char<123) And (_Char>96)) Or ((_Char<91) And (_Char>64)) Or _Char = 95
EndMacro

Procedure isValidVariableName(*VarMem.Character)
  If *VarMem\c<58 And *VarMem\c>47 ; Keine Zahlen am Anfang
    ProcedureReturn 0
  EndIf
  While *VarMem\c
    If Not isValidChar(*VarMem\c) ; Jedes Zeichen prüfen.
      ProcedureReturn 0
    EndIf
    *VarMem + 1
  Wend
  ProcedureReturn 1 ; Variable ist ok
EndProcedure


time = ElapsedMilliseconds()
For i = 1 To 100000
  isValidVariableName(@"_char1")
  isValidVariableName(@"0invlaid")
  isValidVariableName(@"sehrlangername")
Next

Debug ElapsedMilliseconds()-time
Danke schon im vorraus, cxAlex

Verfasst: 30.09.2008 16:30
von STARGÅTE
ich würde das aber dann mit Regulären Ausdrücken machen:

Und auf folgenden String Prüfen:

"\w*"

\w sind genau die Zugelassenene Zeichen ...

Verfasst: 30.09.2008 16:35
von ts-soft
Mußte nochmal prüfen, ist aber mehr als doppelt so schnell, wenns stimmen
sollte :mrgreen:

Code: Alles auswählen

Procedure isValidVariableName(*VarMem.Character)
  If *VarMem\c < 58 And *VarMem\c > 47 ; Keine Zahlen am Anfang
    ProcedureReturn 0
  EndIf
  While *VarMem\c
      Select *VarMem\c
        Case 48 - 57, 65 - 90, 97 - 122, 95
        Default
          ProcedureReturn 1
      EndSelect
    *VarMem + 1
  Wend
  ProcedureReturn 1 ; Variable ist ok
EndProcedure

Verfasst: 30.09.2008 16:43
von cxAlex
@ts-soft:

leider ergibt bei deinem Algo folgender Code 'True' :

Code: Alles auswählen

Debug isValidVariableName(@"#!°")

Verfasst: 30.09.2008 16:43
von STARGÅTE
Hier ein Beispiel:

Code: Alles auswählen

CreateRegularExpression(0, "^[a-zA-Z_]\w*\w?$")

Procedure isValidVariableName(Variable$)
 ProcedureReturn MatchRegularExpression(0, Variable$)
EndProcedure

 Debug isValidVariableName("_char1") 
 Debug isValidVariableName("0invlaid") 
 Debug isValidVariableName("sehrlangername") 
 Debug isValidVariableName("BöserName") 
 Debug isValidVariableName("großerName") 
 Debug isValidVariableName("x") 
 Debug isValidVariableName("1") 

Verfasst: 30.09.2008 16:44
von edel
cx 3307
regex 21248
ts 483

Code: Alles auswählen

#n = 10000000

Global regex = CreateRegularExpression(#PB_Any,"^[a-z_][a-z0-9_]*$",1)

Procedure isValidVariableName2(Var.s) 
  If MatchRegularExpression(regex,Var)
    ProcedureReturn #True 
  EndIf   
EndProcedure 


Macro isValidChar(_Char) 
  ; Gültige Zeichen 
  ((_Char<58) And (_Char>47)) Or ((_Char<123) And (_Char>96)) Or ((_Char<91) And (_Char>64)) Or _Char = 95 
EndMacro 

Procedure isValidVariableName(*VarMem.Character) 
  If *VarMem\c<58 And *VarMem\c>47 ; Keine Zahlen am Anfang 
    ProcedureReturn 0 
  EndIf 
  While *VarMem\c 
    If Not isValidChar(*VarMem\c) ; Jedes Zeichen prüfen. 
      ProcedureReturn 0 
    EndIf 
    *VarMem + 1 
  Wend 
  ProcedureReturn 1 ; Variable ist ok 
EndProcedure 

Procedure isValidVariableName3(*VarMem.Character) 
  If *VarMem\c < 58 And *VarMem\c > 47 ; Keine Zahlen am Anfang 
    ProcedureReturn 0 
  EndIf 
  While *VarMem\c 
      Select *VarMem\c 
        Case 48 - 57, 65 - 90, 97 - 122, 95 
        Default 
          ProcedureReturn 1 
      EndSelect 
    *VarMem + 1 
  Wend 
  ProcedureReturn 1 ; Variable ist ok 
EndProcedure

t0 = ElapsedMilliseconds() 
For i = 1 To #n
  isValidVariableName(@"_char1") 
  isValidVariableName(@"0invlaid") 
  isValidVariableName(@"sehrlangername") 
Next 
t0 = ElapsedMilliseconds() - t0

t1 = ElapsedMilliseconds() 
For i = 1 To #n
  isValidVariableName2("_char1") 
  isValidVariableName2("0invlaid") 
  isValidVariableName2("sehrlangername") 
Next 
t1 = ElapsedMilliseconds() - t1

t2 = ElapsedMilliseconds() 
For i = 1 To #n
  isValidVariableName3(@"_char1") 
  isValidVariableName3(@"0invlaid") 
  isValidVariableName3(@"sehrlangername") 
Next 
t2 = ElapsedMilliseconds() - t2

MessageRequester("",Str(t0)+#LF$+Str(t1)+#LF$+Str(t2))  
Regex macht zwar viele Sachen viel einfacher, ist aber auch um einiges
langsamer.

Verfasst: 30.09.2008 16:48
von STARGÅTE
@edel

pass mal deine Abfrage an (zB wie meine), denn sonst bekommt "GroßeVar" auch ein TRUE

EDIT : und große Buchstaben werden bei dir nun auch FALSE
A-Z fehlt noch :wink:

Verfasst: 30.09.2008 16:52
von edel
Stimmt, hier sollte von Anfang bis Ende geprueft werden.

Verfasst: 30.09.2008 16:55
von cxAlex
Ich hab jetzt mal ts´ Code angepasst das er auch funktioniert.

Code: Alles auswählen

Select *VarMem\c
  Case 48 - 57, 65 - 90, 97 - 122, 95
Default
  ProcedureReturn 1
EndSelect 
war falsch, richtig:

Code: Alles auswählen

Select *VarMem\c
  Case 48 To 57, 65 To 90, 97 To 122, 95
Default
  ProcedureReturn 0
EndSelect 
Neu ergebnisse nach edels` Code:
ts 1500
cx 1765
regex 8516
ts ist schneller, gehts noch flotter?

TestCode:

Code: Alles auswählen

#n = 10000000

Global regex = CreateRegularExpression(#PB_Any,"[a-z_][a-z0-9_]*",1)

Procedure isValidVariableName2(Var.s)
  If MatchRegularExpression(regex,Var)
    ProcedureReturn #True
  EndIf   
EndProcedure


Macro isValidChar(_Char)
  ; Gültige Zeichen
  ((_Char<58) And (_Char>47)) Or ((_Char<123) And (_Char>96)) Or ((_Char<91) And (_Char>64)) Or _Char = 95
EndMacro

Procedure isValidVariableName(*VarMem.Character)
  If *VarMem\c<58 And *VarMem\c>47 ; Keine Zahlen am Anfang
    ProcedureReturn 0
  EndIf
  While *VarMem\c
    If Not isValidChar(*VarMem\c) ; Jedes Zeichen prüfen.
      ProcedureReturn 0
    EndIf
    *VarMem + 1
  Wend
  ProcedureReturn 1 ; Variable ist ok
EndProcedure

Procedure isValidVariableName3(*VarMem.Character)
  If *VarMem\c < 58 And *VarMem\c > 47 ; Keine Zahlen am Anfang
    ProcedureReturn 0
  EndIf
  While *VarMem\c
      Select *VarMem\c
        Case 48 To 57, 65 To 90, 97 To 122, 95
        Default
          ProcedureReturn 0
      EndSelect
    *VarMem + 1
  Wend
  ProcedureReturn 1 ; Variable ist ok
EndProcedure

t0 = ElapsedMilliseconds()
For i = 1 To #n
  isValidVariableName(@"_char1")
  isValidVariableName(@"0invlaid")
  isValidVariableName(@"sehrlangername")
Next
t0 = ElapsedMilliseconds() - t0

t1 = ElapsedMilliseconds()
For i = 1 To #n
  isValidVariableName2("_char1")
  isValidVariableName2("0invlaid")
  isValidVariableName2("sehrlangername")
Next
t1 = ElapsedMilliseconds() - t1

t2 = ElapsedMilliseconds()
For i = 1 To #n
  isValidVariableName3(@"_char1")
  isValidVariableName3(@"0invlaid")
  isValidVariableName3(@"sehrlangername")
Next
t2 = ElapsedMilliseconds() - t2

MessageRequester("","cx "+Str(t0)+#LF$+"ts "+Str(t1)+#LF$+"regex "+Str(t2)) 

Verfasst: 30.09.2008 16:55
von ts-soft
cxAlex hat geschrieben:@ts-soft:

leider ergibt bei deinem Algo folgender Code 'True' :

Code: Alles auswählen

Debug isValidVariableName(@"#!°")
Sowas hab ich vermutet, hab leider keine zeit und lust zu testen, aber den
Ansatz mit Select sollteste Dir mal durch den Kopf gehen lassen, könnte
schneller sein. :wink:

// edit
zu langsam, hat sich erledigt :lol: