Explode()

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
Domino
Beiträge: 22
Registriert: 21.12.2015 21:28
Computerausstattung: Centrino 2x2GHz, GeForce Graka
Linux 3.16

Explode()

Beitrag 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
;}
Centrino 2x2GHz, GeForce Graka, mehrere Linux Mint u.a. mit Mate, Linux 3.16
Benutzeravatar
Domino
Beiträge: 22
Registriert: 21.12.2015 21:28
Computerausstattung: Centrino 2x2GHz, GeForce Graka
Linux 3.16

Re: Explode()

Beitrag von Domino »

Danke sehr!
Centrino 2x2GHz, GeForce Graka, mehrere Linux Mint u.a. mit Mate, Linux 3.16
Benutzeravatar
Kurzer
Beiträge: 1617
Registriert: 25.04.2006 17:29
Wohnort: Nähe Hamburg

Re: Explode()

Beitrag 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
"Never run a changing system!" | "Unterhalten sich zwei Alleinunterhalter... Paradox, oder?"
PB 6.02 x64, OS: Win 7 Pro x64 & Win 11 x64, Desktopscaling: 125%, CPU: I7 6500, RAM: 16 GB, GPU: Intel Graphics HD 520
Useralter in 2024: 56 Jahre.
Benutzeravatar
mhs
Beiträge: 224
Registriert: 11.01.2009 16:30
Wohnort: Graben
Kontaktdaten:

Re: Explode()

Beitrag 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
;}
Michael Hack

Michael Hack Software :: Softwareentwicklung | Webentwicklung | IT-Dienstleistungen
www.michaelhacksoftware.de :: www.mh-s.de :: www.michael-hack.de
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Explode()

Beitrag 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.
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Explode()

Beitrag von Sicro »

Wird in CodeArchiv unter Strings/ExplodeStringIntoArray.pbi aufgenommen.
Code-Autor: Domino (Code verbessert durch Sicro)
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Antworten