Seite 1 von 1

Explode()

Verfasst: 22.12.2015 15:32
von Domino
So, um nicht nur zu nehmen, sondern auch einmal etwas ans Forum zurückzugeben, fange ich mit ein paar kleinen Hilfsroutinen an - hier: Explode(). Bedarf hatte schon TomS im Beitrag http://www.purebasic.fr/german/viewtopi ... it=explode und mk-soft hat eine sicherlich effiziente, aber für Anfänger nicht so gut nachvollziehbare Lösung geschrieben.

Code: Alles auswählen

EnableExplicit
Dim Zeile.s(30)
Declare.l Explode(Trenner.s, String.s, Array Arr.s(1))
Explode(":", "23:59:42.32", Zeile())

;{ Explode()
; Explode() zerlegt eine Zeichenkette in ihre Bestandteil und das Trennzeichen kann auch eine kpl.
; Zeichenkette sein. Da man in Purebasic keine Felder aus Prozeduren zurückgeben kann, wird das Feld
; einfach als Parameter übergeben und die Ergebnisse dort eingetragen. Die Anzahl der belegten Fel-
; der wird als Integer zurückgegeben. Sollte das Feld nicht genügend Einträge haben, wird -1 zurück-
; gegeben.
Procedure.l Explode(Trenner.s, String.s, Array Arr.s(1))
  Define i.l, Pos.l
  i = 0                                         ;So sähe der Teil bis Until 0 in PHP aus:
  Repeat                                        ;$VolProf = explode(", ", $VolProfStr);
    Pos = FindString(String, Trenner)
    If Pos = 0
      If Len(String) > 0 : Arr(i) = String : String = "" : EndIf
      Break
    EndIf
    Arr(i) = Left(String, Pos-1)
    String = Mid(String, Pos + Len(Trenner))
    i + 1
    If i > ArraySize(Arr()) : ProcedureReturn -1 : EndIf
  Until 0
  ProcedureReturn i
EndProcedure
;}

Re: Explode()

Verfasst: 22.12.2015 15:52
von Domino
Danke sehr!

Re: Explode()

Verfasst: 22.12.2015 15:56
von Kurzer
Also das Auftrennen geht auch einfacher - ohne FindString(), Mid() usw.:

Code: Alles auswählen

EnableExplicit
Define i
For i = 1 To 10
	Debug StringField("23:59:42.32", i, ":")
Next i

Re: Explode()

Verfasst: 22.12.2015 15:58
von mhs
Kleiner Tipp: Verwende generell Integer .i statt Long .l, dann hast du bei x86/x64 Umstellung weniger Probleme.

Ich hab deinen Code mal auf eine LinkedList umgebaut, die verwende ich an der Stelle immer gerne:

Code: Alles auswählen

EnableExplicit

Declare.i Explode(Trenner.s, String.s, List Results.s())

NewList Zeile.s()

Explode(":", "23:59:42.32", Zeile())

ForEach Zeile()
  Debug Zeile()
Next

;{ Explode()
; Explode() zerlegt eine Zeichenkette in ihre Bestandteil und das Trennzeichen kann auch eine kpl.
; Zeichenkette sein. Da man in Purebasic keine Felder aus Prozeduren zurückgeben kann, wird das Feld
; einfach als Parameter übergeben und die Ergebnisse dort eingetragen. Die Anzahl der belegten Fel-
; der wird als Integer zurückgegeben. Sollte das Feld nicht genügend Einträge haben, wird -1 zurück-
; gegeben.
Procedure.i Explode(Trenner.s, String.s, List Results.s())

  Define.i i, Pos
  
  ClearList(Results())

  If Not Len(String) : ProcedureReturn 0 : EndIf
  
  Repeat                                        ;$VolProf = explode(", ", $VolProfStr);
  
    Pos = FindString(String, Trenner)
    
    If Pos = 0
      AddElement(Results())
      Results() = String
      Break
    EndIf
    
    AddElement(Results())
    Results() = Left(String, Pos-1)

    String = Mid(String, Pos + Len(Trenner))
    i + 1

  ForEver
  
  ProcedureReturn i
  
EndProcedure
;}
Hier die gleiche Variante mit StringField: (einfacher und kürzer, dafür nicht die schnellste)

Code: Alles auswählen

EnableExplicit

Declare.i Explode(Trenner.s, String.s, List Results.s())

NewList Zeile.s()

Explode(":", "23:59:42.32", Zeile())

ForEach Zeile()
  Debug Zeile()
Next

;{ Explode()
; Explode() zerlegt eine Zeichenkette in ihre Bestandteil und das Trennzeichen kann auch eine kpl.
; Zeichenkette sein. Da man in Purebasic keine Felder aus Prozeduren zurückgeben kann, wird das Feld
; einfach als Parameter übergeben und die Ergebnisse dort eingetragen. Die Anzahl der belegten Fel-
; der wird als Integer zurückgegeben. Sollte das Feld nicht genügend Einträge haben, wird -1 zurück-
; gegeben.
Procedure.i Explode(Trenner.s, String.s, List Results.s())

  Define.i i, Count
  
  ClearList(Results())

  Count = CountString(String, Trenner)
  
  For i = 1 To Count + 1
    AddElement(Results())
    Results() = StringField(String, i, Trenner)
  Next i
  
  ProcedureReturn ListSize(Results())
  
EndProcedure
;}

Re: Explode()

Verfasst: 19.04.2016 18:17
von Sicro
Domino hat geschrieben:

Code: Alles auswählen

String = Mid(String, Pos + Len(Trenner))
Das ist ein unnötiger Zeitfresser.

Ich habe den Code mit ein paar Verbesserungen neu erstellt:
  • String wird gelassen, wie er ist
  • Array wird in der Größe automatisch angepasst
  • Array wird in großen Schritten vergrößert, damit das Array nicht zu oft angepasst werden muss

Code: Alles auswählen

EnableExplicit

Procedure Explode(Separator$, String$, Array Output$(1))
  Protected ArrayIndex, StartPos, SeparatorPos
  
  ArrayIndex = -1
  StartPos = 1
  
  Repeat
    ArrayIndex + 1
    
    If ArraySize(Output$()) < ArrayIndex
      ReDim Output$(ArrayIndex + 99) ; Wenn Output-Array zu klein ist, es um 100 Elemente vergrößern
    EndIf
    
    SeparatorPos = FindString(String$, Separator$, StartPos)
    If SeparatorPos = 0
      Output$(ArrayIndex) = Mid(String$, StartPos)
      Break
    EndIf
    
    Output$(ArrayIndex) = Mid(String$, StartPos, SeparatorPos - StartPos)
    StartPos = SeparatorPos + 1
  ForEver
  
  ReDim Output$(ArrayIndex) ; Array auf die wirklich notwendige Größe setzen
  
  ProcedureReturn ArrayIndex
EndProcedure

Define CountOfItems, i
Dim Items$(0) ; Hier kann die Größe auch im Voraus vergrößert werden, z. B.: Dim Items$(100)

CountOfItems = Explode(":", "String1:String2:String3", Items$())
For i = 0 To CountOfItems
  Debug Items$(i)
Next

Debug ArraySize(Items$())
Die Verwendung eines Arrays finde ich hier besser, weil man später sehr schnell auf die einzelnen Einträge zugreifen kann, was mit Linked Lists nicht gegeben ist:
PB-Hilfe: SelectElement() hat geschrieben:Anmerkungen

Da verknüpfte Listen intern keinen Index verwenden, springt diese Funktion zwangsläufig zu jedem Element in der Liste, bis die Zielposition erreicht ist, was bei einer großen Liste Zeit benötigt.

Re: Explode()

Verfasst: 22.04.2016 16:02
von Sicro
Wird in CodeArchiv unter Strings/ExplodeStringIntoArray.pbi aufgenommen.
Code-Autor: Domino (Code verbessert durch Sicro)