Code: Alles auswählen
;Debugger aus !!!
; Initialisierung
Global Dim LookupTable.l($FFFF)
Define Ii
For I= 0 To $FFFF
LookupTable(I) = I
Next
LookupTable('Ä') = 'eA'
LookupTable('Ö') = 'eO'
LookupTable('Ü') = 'eU'
LookupTable('ä') = 'ea'
LookupTable('ö') = 'eo'
LookupTable('ü') = 'eu'
LookupTable('ß') = 'ss'
LookupTable($1E9E) = 'SS'
; STARGÅTEs Prozedur
Procedure.s FastReplaceUmlaute(*Text.Character)
Static *Buffer
If *text=0
If *Buffer
FreeMemory(*buffer)
EndIf
*buffer=0
ProcedureReturn ""
EndIf
*Buffer = ReAllocateMemory(*Buffer, MemoryStringLength(*Text, #PB_ByteLength)*2+2,#PB_Memory_NoClear)
Protected *Position.Long = *Buffer
While *Text\c
*Position\l = LookupTable(*Text\c)
If *Position\l & ~$FFFF
*Position + SizeOf(Character)*2
Else
*Position + SizeOf(Character)
EndIf
*Text+ SizeOf(Character)
Wend
*Position\l=0
ProcedureReturn PeekS(*Buffer, (*Position-*Buffer)/SizeOf(Character))
EndProcedure
Structure CharacterDouble
StructureUnion
c.c
l.l
EndStructureUnion
EndStructure
Procedure.s ReplaceUmlauteGPI(*text.Character)
Static *buffer, Buffersize
If *text=0
If *buffer
FreeMemory(*buffer)
EndIf
*buffer=0
Buffersize=0
ProcedureReturn ""
EndIf
Protected textlen=MemoryStringLength(*text,#PB_ByteLength) *2+2
If Buffersize<textlen
textlen+1024;damit nicht dauernd neu angefordert wird
*buffer=ReAllocateMemory(*buffer,textlen,#PB_Memory_NoClear)
Buffersize=textlen
EndIf
Protected *out.CharacterDouble=*buffer
While *text\c ;1.Zeichen im Text bei Start
Select *text\c
Case 0 To 127:*out\c=*text\c:*out+SizeOf(character)
Case 'Ä' : *out\l='eA':*out+SizeOf(long)
Case 'Ö' : *out\l='eO':*out+SizeOf(long)
Case 'Ü' : *out\l='eU':*out+SizeOf(long)
Case 'ä' : *out\l='ea':*out+SizeOf(long)
Case 'ö' : *out\l='eo':*out+SizeOf(long)
Case 'ü' : *out\l='eu':*out+SizeOf(long)
Case 'ß' : *out\l='ss':*out+SizeOf(long)
Case $1E9E:*out\l='sS':*out+SizeOf(long)
Default:*out\c=*text\c:*out+SizeOf(character)
EndSelect
*text + SizeOf(Character) ;zum nächsten Zeichen im Text
Wend
*out\c=0
ProcedureReturn PeekS(*buffer)
EndProcedure
Procedure.s ReplaceUmlaute(*text.Character)
;Ä ä Ö ö Ü ü ß "
;AeaeOeoeUeuess"
Static mem
If *text=0
If mem
FreeMemory(mem)
EndIf
mem=0
ProcedureReturn ""
EndIf
Protected newlg = MemoryStringLength(*text, #PB_ByteLength) * 2+2
mem= ReAllocateMemory(mem,newlg,#PB_Memory_NoClear);nicht jedesmal neu allocate!
Protected new$, *buff.Character=mem
While *text\c ;1.Zeichen im Text bei Start
Select *text\c
Case 0 To 127 : *buff\c = *text\c ;Speedup!
Case 'Ä' : *buff\c = 'A' : *buff + SizeOf(Character) : *buff\c = 'e'
Case 'Ö' : *buff\c = 'O' : *buff + SizeOf(Character) : *buff\c = 'e'
Case 'Ü' : *buff\c = 'U' : *buff + SizeOf(Character) : *buff\c = 'e'
Case 'ä' : *buff\c = 'a' : *buff + SizeOf(Character) : *buff\c = 'e'
Case 'ö' : *buff\c = 'o' : *buff + SizeOf(Character) : *buff\c = 'e'
Case 'ü' : *buff\c = 'u' : *buff + SizeOf(Character) : *buff\c = 'e'
Case 'ß' : *buff\c = 's' : *buff + SizeOf(Character) : *buff\c = 's'
Default : *buff\c = *text\c
EndSelect
*text + SizeOf(Character) ;zum nächsten Zeichen im Text
*buff + SizeOf(Character) ;zum nächsten Zeichen im Textbuffer
Wend
*buff\c=0
ProcedureReturn PeekS(mem)
EndProcedure
Dim text$(5):maxtext=6
text$(0)="Über Äpfel Rüben Straße ärgert Ösil + Bär"
text$(1)="abcdefghijklmnopqrstuvwxyzäöüßABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜß"
text$(2)="Ein Text ohne Umlaute"
text$(3)="ääääööööööööööüüüüüüüüüüüüüüßßßßßßßßßßßßßßßÄÄÄÄÄÄÄÄÄÄÄÖÖÖÖÖÖÖÖÖÖÖÖÜÜÜÜÜÜÜÜÜÜÜÜ"
text$(4)="!§&/)(&/)(%/!(&)/(19263789126398463978"
text$(5)="aÄbÄcÖeÖdÜeß"
max = 100000*10
s = ElapsedMilliseconds()
For j = 1 To max
xx$ = ReplaceString(ReplaceString(ReplaceString(ReplaceString(ReplaceString(ReplaceString(ReplaceString(text$(j%maxtext), "Ä", "Ae"), "Ü", "Ue"), "Ö", "Oe"), "ä", "ae"), "ü", "ue"), "ö", "oe"), "ß", "ss")
Next
ss = ElapsedMilliseconds() - s
s = ElapsedMilliseconds()
For j = 1 To max
new$ = ReplaceUmlaute(@text$(j%maxtext))
Next
ReplaceUmlaute(0)
su = ElapsedMilliseconds() - s
s = ElapsedMilliseconds()
For j = 1 To max
fast$ = FastReplaceUmlaute(@text$(j%maxtext))
Next
FastReplaceUmlaute(0)
sv = ElapsedMilliseconds() - s
s = ElapsedMilliseconds()
For j = 1 To max
fastGPI$ = ReplaceUmlauteGPI(@text$(j%maxtext))
Next
ReplaceUmlauteGPI(0)
sg = ElapsedMilliseconds() - s
info$ + #LF$
info$ + xx$ + " -PB:" + #TAB$ + Str(ss) + #LF$
info$ + new$ + " -ich" + #TAB$ + Str(su) + #LF$
info$ + fast$ + " -STARGÅTE" + #TAB$ + Str(sv) + #LF$
info$ + fastGPI$ + " -gpi" + #TAB$ + Str(sg) + #LF$
MessageRequester("", info$)
Ich hab mal meine eigene Variante geschrieben. Die Ergebnisse sind lustig, zumindest bei mir.
Ich hab mir nicht nehmen lassen, alle Varianten anzugleichen. Der große Vorteil der "FAST"-Routine ist, das er den Speicher nicht immer neu anfordert, sondern wiederverwendet. Das beschleunigt am meisten, nicht die Lookup-Tabelle.
Ich hab bei allen Varianten auch hinzugefügt, das der angeforderte Speicher nicht mehr gelöscht wird. Dafür muss ich jetzt natürlich das Null-Abschluss-Byte setzen.
Genauso hab ich die Variable "new$" gekillt, sondern gebe direkt bei Return das Peeks() zurück. Das spart umkopieren von Strings.
Um den dauerhaft reservierten Speicher wieder freizugeben, kann man die Funktion mit 0 als Parameter aufrufen. Das hab ich mal beim Messen am Schluss eingefügt.
Meine Routine geht mit der Speicherreservierung etwas klüger um. Wenn der Buffer schon groß genug ist, wird er nicht verkleinert. Zudem reserviert er +1024 Bytes, damit nicht immer wieder neu angefordert wird, wenn der nächste String ein paar Byte größer wird.
Was auch beschleunigt hat, als ersten Case 0-127 einzufügen. Das sind die normalen englischen Zeichen und Satzzeichen. Damit muss zu 99% nur ein Fall getestet werden. Geht schneller.
Den Benchmark hab ich angepasst, das er verschieden lange strings hernimmt. Und 10x mehr durchläufe gibt es, weil sonst die Ergebnisse zu nah beieinander liegen.
Die Zeiten liegen jetzt deutlich näher zusammen. Meine Lösung ist, dank weniger Speicherfreigaben, aktuell die schnellste
