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
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' :
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

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' :
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.
// edit
zu langsam, hat sich erledigt
