StringBetween()

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
User avatar
bgeraghty
User
User
Posts: 52
Joined: Wed Apr 02, 2014 12:45 am
Location: irc.ibotched.it:+6697
Contact:

StringBetween()

Post by bgeraghty »

Please let me know if I've Re-Invented any PB-Wheels in writing this, but I've found it infinitely useful in string-parsing:

Code: Select all

Procedure.s StringBetween(SourceString$, String1$, String2$, OccurenceNumber.i=0, StartPos.i=0)
  Start1.i = StartPos
  End1.i = 0
  If OccurenceNumber <> 0
    For I = 0 To OccurenceNumber
      Select I
        Case 0
          Start1 = FindString(SourceString$, String1$, Start1) + Len(String1$)
        Default
          Start1 = FindString(SourceString$, String1$, Start1) + Len(String1$)
      EndSelect
    Next
  Else
    Start1 = FindString(SourceString$, String1$, 0) + Len(String1$)
  EndIf
  End1 = FindString(SourceString$, String2$, Start1)
  End1 - Start1
  ProcedureReturn Mid(SourceString$, Start1, End1)
EndProcedure

........

String$ = "<title>My New Web Site</title>"
Result$ = StringBetween(String$, "<title>", "</title>") ; = "My New Web Site"
End
SolveMyIssue_() - No QuickHelp available.
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: StringBetween()

Post by c4s »

Here is a slightly different approach that optionally gives you the ending position (0 if not found):

Code: Select all

Procedure.s StringExtract(String.s, Before.s, After.s, *PositionEnd.Integer=0, PositionStart=1)
	Protected PositionBefore.i, PositionAfter.i

	If *PositionEnd : *PositionEnd\i = 0 : EndIf

	If PositionStart < 1 : ProcedureReturn "" : EndIf

	PositionBefore = FindString(String, Before, PositionStart)
	If PositionBefore = 0 : ProcedureReturn "" : EndIf

	PositionBefore + Len(Before)

	PositionAfter = FindString(String, After, PositionBefore)
	If PositionAfter = 0 : ProcedureReturn "" : EndIf

	If *PositionEnd : *PositionEnd\i = PositionAfter + Len(After) : EndIf

	ProcedureReturn Mid(String, PositionBefore, PositionAfter - PositionBefore)
EndProcedure


String$ = "<title>My First Web Site</title><title>My Second Web Site</title>"
Debug String$
Debug "1. Result: " + StringExtract(String$, "<title>", "</title>", @EndPosition)
Debug "1. Ending Position: " + EndPosition
Debug "2. Result: " + StringExtract(String$, "<title>", "</title>", @EndPosition, EndPosition)
Debug "2. Ending Position: " + EndPosition
Debug "3. Result: " + StringExtract(String$, "<title>", "</title>", @EndPosition, EndPosition)
Debug "3. Ending Position: " + EndPosition
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
Kiffi
Addict
Addict
Posts: 1357
Joined: Tue Mar 02, 2004 1:20 pm
Location: Amphibios 9

Re: StringBetween()

Post by Kiffi »

here is my try (without OccurenceNumber and StartPos):

Code: Select all

Procedure.s StringBetween2(SourceString$, String1$, String2$)
 Protected ReturnValue.s
 ReturnValue = SourceString$
 ReturnValue = StringField(ReturnValue, 2, String1$)
 ReturnValue = StringField(ReturnValue, 1, String2$)
 ProcedureReturn ReturnValue
EndProcedure

String$ = "<title>My New Web Site</title>"
Result$ = StringBetween2(String$, "<title>", "</title>") ; = "My New Web Site"
Debug Result$
Greetings ... Peter
Hygge
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: StringBetween()

Post by StarBootics »

An very old code posted long ago on the French forum

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Nom du projet : StringBetween two Strings
; Nom du fichier : StringBetween.pb
; Version du fichier : 1.0.0
; Programmation : OK
; Programmé par : Dr. Dri
; Date : 29-06-2011
; Mise à jour : 29-06-2011
; Code PureBasic : 4.60
; Plateforme : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Procedure.s StringBetween(String.s, LString.s, RString.s) ; Returns the string between the two strings
  
  ;// Author : Dr. Dri
  
  Protected Between.s, LIndex.l, RIndex.l 
  
  LIndex = FindString(string, LString, 0) 
  RIndex = FindString(string, RString, 0) 
  
  If LIndex And RIndex 
    LIndex + Len(LString) 
    Between = Mid(String, LIndex, RIndex - LIndex) 
  EndIf 
  
  ProcedureReturn Between 
EndProcedure 

; Debug StringBetween("Droopy", "Dr", "py")

; <<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< FIN DU FICHIER <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<
The Stone Age did not end due to a shortage of stones !
mestnyi
Addict
Addict
Posts: 1000
Joined: Mon Nov 25, 2013 6:41 am

Re: StringBetween()

Post by mestnyi »

StarBootics
I changed a little bit now, you can include the search string in the search result.

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Nom du projet : StringBetween two Strings
; Nom du fichier : StringBetween.pb
; Version du fichier : 1.0.0
; Programmation : OK
; Programmé par : Dr. Dri
; Date : 29-06-2011
; Mise à jour : 29-06-2011
; Code PureBasic : 4.60
; Plateforme : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Procedure.s StringBetween(String.s, LString.s, RString.s, Along.b ) ; Returns the string between the two strings
  
  ;// Author : Dr. Dri
  
  Protected Between.s, LIndex.i, RIndex.i 
  
  LIndex = FindString(string, LString, 0) 
  RIndex = FindString(string, RString, 0) 
  
  If LIndex And RIndex 
    If Along
      RIndex + 1
    Else
      LIndex + Len(LString) 
    EndIf
    Between = Mid(String, LIndex, (RIndex - LIndex)) 
  EndIf 
  
  ProcedureReturn Between 
EndProcedure 

Procedure$ LoadFromFile(File$)
   Static Name$,ReadWin$,ClosingBrace
   ;Protected  Line
   Protected OpFile,StringFormat,String$,ReadString$,ReadProcedure$,ReadFunction$
   OpFile = OpenFile(#PB_Any, File$)
   If OpFile  
     CompilerIf #PB_Compiler_Unicode
       StringFormat = ReadStringFormat(OpFile)
     CompilerElse
       StringFormat = #PB_Ascii
     CompilerEndIf
     While Eof(OpFile) = 0 :Line +1
       ReadString$ = ReadString(OpFile, StringFormat)
      ;Debug StringBetween(ReadString$, StringBetween(ReadString$, "OpenWindow", "(",1), ")",0)
      Debug StringBetween(ReadString$, "OpenWindow", ")",1)
      
      String$ + Str(Line)+") "+ReadString$ + #CRLF$  
     Wend
     CloseFile(OpFile)
    ProcedureReturn String$
  Else
    MessageRequester("", "Not find "+File$)
    End 
  EndIf   
EndProcedure 
String$ = LoadFromFile("C:\Users\mestnyi\Documents\Test.pb")
 
; <<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< FIN DU FICHIER <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: StringBetween()

Post by StarBootics »

mestnyi wrote:StarBootics
I changed a little bit now, you can include the search string in the search result.
As I said, I'm not the author of the code. Furthermore, this code came from the Droopy lib, I have extracted it from the lib since it contains many Windows Only functions and I my computer are Linux Only.

Anyway, having the source code it's something I like, the code can be modified to suit all needs.

Best regards
StarBootics
The Stone Age did not end due to a shortage of stones !
User avatar
Vera
Addict
Addict
Posts: 858
Joined: Tue Aug 11, 2009 1:56 pm
Location: Essen (Germany)

Re: StringBetween()

Post by Vera »

Hi bgeraghty,

I tried the offered OccurenceNumber and it returns wrong first results if the passed value doesn't fit exactly. An additional if-condition can prevent that effect. Have a try:

Code: Select all

 Procedure.s StringBetween(SourceString$, String1$, String2$, OccureNum.i=0, StartPos.i=0)
  Start1.i = StartPos
  End1.i = 0
  If OccureNum <> 0
    For I = 0 To OccureNum
      Select I
        Case  0
          Start1 = FindString(SourceString$, String1$, Start1) + Len(String1$)
 ;         Debug "Case0 " + Str(Start1) + " - " + Str(I)
        Default
;           If FindString(SourceString$, String1$, Start1) = 0      ; additional condition
;             Start1 = 0
;           EndIf
          Start1 = FindString(SourceString$, String1$, Start1) + Len(String1$)
;          Debug "Def " + Str(Start1) + " - " + Str(I)
      EndSelect
    Next
  Else
    Start1 = FindString(SourceString$, String1$, 0) + Len(String1$)
  EndIf
  End1 = FindString(SourceString$, String2$, Start1)
  End1 - Start1
  ProcedureReturn Mid(SourceString$, Start1, End1)
EndProcedure


String$ = "<title>My New Web Site</title>"
Debug StringBetween(String$, "<title>", "</title>") ; = "My New Web Site"
Debug StringBetween(String$, "<title>", "</title>",1)
Debug StringBetween(String$, "<title>", "</title>",2)

Debug " - - - "
String2$ = "<title>My New Web Site</title> or <title>My Old Site</title> as well <title>Any Site</title>"
Debug StringBetween(String2$, "<title>", "</title>")
Debug StringBetween(String2$, "<title>", "</title>",1)
Debug StringBetween(String2$, "<title>", "</title>",2)
Debug StringBetween(String2$, "<title>", "</title>",3)

End 
Say e.g. you wanted to get all contains from a table (td), wouldn't it be better to check the amount of occurences first before passing them or a specific one on?

@all ~ thanks for the alternativ examples :-)

greets ~ Vera
User avatar
bgeraghty
User
User
Posts: 52
Joined: Wed Apr 02, 2014 12:45 am
Location: irc.ibotched.it:+6697
Contact:

Re: StringBetween()

Post by bgeraghty »

Thread Resurrected!

I have been coding a bit more again, and I'm optimizing some old routines for use in current projects.

It's not as readable, but it should be a bit more compact/streamlined at least.

Code: Select all

Procedure.s StringBetween(SourceString$, StartString$, EndString$, OccurrenceNumber.i=0, StartPosition.i=0)
  Protected A.i = StartPosition, B.i = 0, I.i = 0, Result.s = ""
  For I = 0 To OccurrenceNumber : A = FindString(SourceString$, StartString$, A) + Len(StartString$) : Next
  B = FindString(SourceString$, EndString$, A) : If B : B - A : Result = Mid(SourceString$, A, B) : EndIf
  ProcedureReturn Result
EndProcedure
Amazing how far we come, and how programming style changes over the years as we learn.
SolveMyIssue_() - No QuickHelp available.
BarryG
Addict
Addict
Posts: 3322
Joined: Thu Apr 18, 2019 8:17 am

Re: StringBetween()

Post by BarryG »

This is what I use (when I know there's only one occurrence):

Code: Select all

Procedure.s PluckString(text$,left$,right$)
  l=FindString(text$,left$)
  r=FindString(text$,right$,l+1)
  If l>0 And r>l
    p$=Mid(Left(text$,r-1),l+Len(left$))
  EndIf
  ProcedureReturn p$
EndProcedure

Debug PluckString("<title>My New Web Site</title>","<title>","</title>")
User avatar
bgeraghty
User
User
Posts: 52
Joined: Wed Apr 02, 2014 12:45 am
Location: irc.ibotched.it:+6697
Contact:

Re: StringBetween()

Post by bgeraghty »

Hehe, nice. Bonus:

Code: Select all

Global SampleString$ = "a;sldfkjasldfjka<example>test</example>;aljfpeofjapefakjfaia49a7yga80a<example>hello</example>a;alkfjpfjip98f9jvbaeirguahp9<example>DidYouFindMe?</example>akldfjpj34"
Global SearchStart$ = "<example>" : Global SearchEnd$ = "</example>"

Procedure.s StringBetween(SourceString$, StartString$, EndString$, OccurrenceNumber.i=0, StartPosition.i=0)
  Protected A.i = StartPosition, B.i = 0, I.i = 0, Result.s = ""
  For I = 0 To OccurrenceNumber : A = FindString(SourceString$, StartString$, A) + Len(StartString$) : Next
  B = FindString(SourceString$, EndString$, A) : If B : B - A : Result = Mid(SourceString$, A, B) : EndIf
  ProcedureReturn Result
EndProcedure

Debug StringBetween(SampleString$, SearchStart$, SearchEnd$)

Procedure.s AllBetween(SourceString$, StartString$, EndString$)
  Protected X.i = CountString(SourceString$, SearchStart$) : Protected Y.i = 0 : Protected Result.s = ""
  If X : For Y = 0 To X-1 : Result + StringBetween(SourceString$, StartString$, EndString$, Y) + #CRLF$ : Next : EndIf
  ProcedureReturn Result
EndProcedure

Debug AllBetween(SampleString$, SearchStart$, SearchEnd$)
SolveMyIssue_() - No QuickHelp available.
AZJIO
Addict
Addict
Posts: 1360
Joined: Sun May 14, 2017 1:48 am

Re: StringBetween()

Post by AZJIO »

Code: Select all

EnableExplicit

Procedure.s StringBetween(text$, str1$, str2$, *start.Integer)
	Protected Pos1, Pos2
	Pos1 = FindString(text$, str1$, *start\i)
	If Pos1
		Pos1 + Len(str1$)
		Pos2 = FindString(text$, str2$, Pos1 + 1)
		If Pos2
			*start\i = Pos2 + Len(str2$)
			ProcedureReturn Mid(text$, Pos1, Pos2 - Pos1)
		EndIf
	EndIf
	*start\i = -1
EndProcedure

Define pos = 0

Repeat
	Debug "|" + StringBetween("<b>fuf</b><b>qwe</b>", "<b>", "</b>", @pos) + "|"
Until pos = -1
.

Code: Select all

EnableExplicit

Procedure.s StringBetween(text$, str1$, str2$, start = 0, new = 0)
	Protected Pos1, Pos2;, res$
	Static Pos
	If new
		Pos = 0
		If start
			Pos = start
		EndIf
	EndIf

	Pos1 = FindString(text$, str1$, Pos)
	If Pos1
		Pos1 + Len(str1$)
		Pos2 = FindString(text$, str2$, Pos1 + 1)
		If Pos2
			Pos = Pos2 + Len(str2$)
			ProcedureReturn Mid(text$, Pos1, Pos2 - Pos1)
		EndIf
	EndIf
EndProcedure

Debug "|" + StringBetween("<b>fuf</b><b>qwe</b>", "<b>", "</b>", 0) + "|"
Debug "|" + StringBetween("<b>fuf</b><b>qwe</b>", "<b>", "</b>", 0) + "|"
Debug "|" + StringBetween("<b>fuf</b><b>qwe</b>", "<b>", "</b>", 0) + "|"
Debug "|" + StringBetween("<b>fuf</b><b>qwe</b>", "<b>", "</b>", 10, 1) + "|"
Debug "|" + StringBetween("<b>fuf</b><b>qwe</b>", "<b>", "</b>", 0) + "|"
User avatar
Thorsten1867
Addict
Addict
Posts: 1366
Joined: Wed Aug 24, 2005 4:02 pm
Location: Germany

Re: StringBetween()

Post by Thorsten1867 »

The whole thing minimalist:

Code: Select all

Procedure.s StringBetween(String.s, StartString.s, EndString.s)
  String = StringField(String, 2, StartString)
  ProcedureReturn StringField(String, 1, EndString)
EndProcedure

String$ = "<title>Example String</title>"
Debug StringBetween(String$, "<title>", "</title>")

OR as a module

Code: Select all

;/ ==========================
;/ =    ToolsModule.pbi    =
;/ ==========================
;/
;/ [ PB V5.7x - V6.0 / 64Bit / all OS ]
;/
;/ © 2022 Thorsten1867 (06/2022)
;/

;- ===== String =====

DeclareModule String
  
  Declare.s Between(String.s, StartString.s, EndString.s)
  Declare   Split(String.s, Array Result.s(1), Separator.s=" ")
  Declare.s Join(Array Result.s(1), Separator.s=" ")
  Declare   MulitSplit(String.s, Array Result.s(1), Separator.s=" ")
  Declare   Token(String.s, Array Result.s(1), Array Separators.s(1))
  Declare   Extract(String.s, Array Result.s(1), StartToken.s, EndToken.s)
  
EndDeclareModule

Module String
  
  Procedure   Split(String.s, Array Result.s(1), Separator.s=" ")
    ; by wilbert
    Define S.String, *S.Integer = @S
    Define.i aSize, i, Pos, sLen
    
    aSize = CountString(String, Separator)
    sLen  = Len(Separator)
    
    ReDim Result(aSize)
    
    *S\i = @String
    
    While i < aSize
      Pos = FindString(S\s, Separator)
      Result(i) = PeekS(*S\i, Pos - 1)
      *S\i + (Pos + sLen - 1) << #PB_Compiler_Unicode
      i + 1
    Wend
    
    Result(i) = S\s
    *S\i = 0
    
  EndProcedure

  Procedure.s Join(Array Result.s(1), Separator.s=" ")
    ; by wilbert
    Define.i aSize, i, sLen, tLen, *Buffer
    
    aSize = ArraySize(Result())
    sLen = Len(Separator)
    
    For i = 0 To aSize
      tLen + Len(Result(i)) + sLen
    Next
    
    tLen - sLen
    
    Dim Buffer.c(tLen)
    
    *Buffer = @Buffer()
    CopyMemoryString(Result(0), @*Buffer)
    For i = 1 To aSize
      CopyMemoryString(Separator)
      CopyMemoryString(Result(i))
    Next
    
    ProcedureReturn PeekS(@Buffer())
  EndProcedure
  
  Procedure   MulitSplit(String.s, Array Result.s(1), Separators.s=" ")
    Define.i c, sLen, aSize, Pos, EndPos, StartPos = 1
    
    NewList Token$()
    
    sLen = Len(String)
    
    While StartPos < sLen
      
      EndPos = sLen
      
      For c=1 To Len(Separators)
        
        If Mid(String, StartPos, 1) = Mid(Separators, c, 1)
          StartPos + 1
          Endpos = StartPos
          Break
        Else  
          Pos = FindString(String, Mid(Separators, c, 1), StartPos)
          If Pos And Pos < EndPos : EndPos = Pos : EndIf 
        EndIf  
  
      Next
  
      If EndPos <> StartPos
        If AddElement(Token$()) : Token$() = Mid(String, StartPos, EndPos - Startpos) : EndIf 
      EndIf
      
      StartPos = EndPos
    Wend
    
    aSize = ListSize(Token$()) - 1
    
    If aSize >= 0
    
      ReDim Result(aSize)
      
      c = 0
      
      ForEach Token$()
        Result(c) = Token$()
        c + 1
      Next 
      
    EndIf
    
  EndProcedure  
  
  Procedure   Token(String.s, Array Result.s(1), Array Separator.s(1))
    Define.i sLen, spSize, spLen, aSize
    Define.i i, Pos, EndPos, StartPos = 1

    NewList Token$()
    
    sLen   = Len(String)
    spSize = ArraySize(Separator())
    
    While StartPos < sLen
      
      spLen  = 0
      EndPos = sLen
      
      For i=0 To spSize
        
        If Mid(String, StartPos, Len(Separator(i))) = Separator(i)
          StartPos + Len(Separator(i))
          Endpos = StartPos
          Break
        Else  
          Pos = FindString(String, Separator(i), StartPos)
          If Pos And Pos < EndPos
            EndPos = Pos
            spLen  = Len(Separator(i))
          EndIf   
        EndIf
        
      Next

      If EndPos <> StartPos
        If AddElement(Token$()) : Token$() = Mid(String, StartPos, EndPos - Startpos) : EndIf 
      EndIf

      StartPos = EndPos + SpLen
    Wend
    
    aSize = ListSize(Token$()) - 1
    If aSize >= 0
    
      ReDim Result(aSize)
      
      c = 0
      
      ForEach Token$()
        Result(c) = Token$()
        c + 1
      Next 
      
    EndIf
    
  EndProcedure  
  
  Procedure   Extract(String.s, Array Result.s(1), StartToken.s, EndToken.s)
    Define.i sLen, aSize, Pos, EndPos, StartPos, Idx
    
    sLen  = Len(String)
    aSize = CountString(String, StartToken) - 1
    
    ReDim Result(aSize)
    
    Pos = 1
    StartPos = Pos
    
    While Pos
      
      Pos = FindString(String, StartToken, StartPos)
      If Pos 
        
        StartPos = Pos + Len(StartToken)
        
        EndPos = FindString(String, EndToken, StartPos)
        If StartPos < EndPos
          Result(Idx) = Mid(String, StartPos, EndPos - StartPos)
          Idx + 1
        EndIf  
        
        If EndPos : StartPos = Endpos + Len(EndToken) : EndIf
        
      EndIf  

    Wend  
    
  EndProcedure  
  
  Procedure.s Between(String.s, StartString.s, EndString.s)
    String = StringField(String, 2, StartString)
    ProcedureReturn StringField(String, 1, EndString)
  EndProcedure
  
EndModule  


;- ===== File =====

DeclareModule  File
  
  Declare.i Exists(File.s)
  
  Declare.i ValidPath(Path.s) 
  
EndDeclareModule

Module File
  
  Procedure.i Exists(File.s)    ; Does the file exist?
    
    If FileSize(File) >= 0
      ProcedureReturn #True
    EndIf
    
    ProcedureReturn #False
  EndProcedure
  
  Procedure.i ValidPath(Path.s) ; Is the path valid?
    
    If FileSize(Path) = -2
      ProcedureReturn #True
    EndIf  
    
    ProcedureReturn #False
  EndProcedure
  
  Procedure.s Directory(Path.s) ; Creates directory if it does not exist
    
    If Right(Path, 1) <> #PS$ : Path + #PS$ : EndIf
    
    If FileSize(Path) = -2
      ProcedureReturn Path
    Else  
      If CreateDirectory(Path)
        ProcedureReturn Path
      EndIf
    EndIf  

  EndProcedure  
  
EndModule  

;- ========  Module - Example ========

CompilerIf #PB_Compiler_IsMainFile

#Example = 0

; 0: String between
; 1: Split strings
; 2: Split with multiple separators
; 3: Token
; 4: Extrakt from token

  Select #Example
    Case 0 ;{ String between
    String$ = "<title>My String Between</title>"
    Debug String::Between(String$, "<title>", "</title>")
    ;}
    Case 1 ;{ Split & join strings
      
      Dim Result.s(0)
      
      Test$ = "This is a test string to see if split and join are working."
      
      String::Split(Test$, Result())
      
      For i = 0 To ArraySize(Result())
        Debug Str(i) + ": " + Result(i)
      Next
      
      Debug "---------------------"
      
      Result$ = String::Join(Result(), "_")
      
      Debug "=> " + Result$
      ;}
    Case 2 ;{ Split with multiple separators
      
      Dim Result.s(0)
      
      Test$ = "Command = DIR " + #DOUBLEQUOTE$ + "*.*" + #DOUBLEQUOTE$ + ", /s" + " " 
      
      String::MulitSplit(Test$, Result(), "=, ")
      
      For i = 0 To ArraySize(Result())
        Debug Str(i) + ": " + Result(i)
      Next
      ;}
    Case 3 ;{ Token
      
      Dim Result.s(0)
      Dim Separator.s(1)
      
      Separator(0) = "<b>"
      Separator(1) = "</b>"
      
      Test$ = "This is a <b>text</b> with <b>bold</b> words."
      
      String::Token(Test$, Result(), Separator())
      
      For i = 0 To ArraySize(Result())
        Debug Str(i) + ": " + Result(i)
      Next
      ;}
    Case 4 ;{ Extrakt from token
      
      Dim Result.s(0)
      
      Test$ = "This is a <b>text</b> with <b>bold</b> words."
      
      String::Extract(Test$, Result(), "<b>", "</b>")
      
      For i = 0 To ArraySize(Result())
        Debug Str(i) + ": " + Result(i)
      Next
      ;}
  EndSelect    

CompilerEndIf
Translated with http://www.DeepL.com/Translator

Download of PureBasic - Modules
Download of PureBasic - Programs

[Windows 11 x64] [PB V5.7x]
User avatar
bgeraghty
User
User
Posts: 52
Joined: Wed Apr 02, 2014 12:45 am
Location: irc.ibotched.it:+6697
Contact:

Re: StringBetween()

Post by bgeraghty »

I like the idea of using StringField() for this, didn't think of that.
Thorsten1867 wrote: Sun Jul 17, 2022 8:29 am The whole thing minimalist:

Code: Select all

Procedure.s StringBetween(String.s, StartString.s, EndString.s)
  String = StringField(String, 2, StartString)
  ProcedureReturn StringField(String, 1, EndString)
EndProcedure

String$ = "<title>Example String</title>"
Debug StringBetween(String$, "<title>", "</title>")

OR as a module

Code: Select all

;/ ==========================
;/ =    ToolsModule.pbi    =
;/ ==========================
;/
;/ [ PB V5.7x - V6.0 / 64Bit / all OS ]
;/
;/ © 2022 Thorsten1867 (06/2022)
;/

;- ===== String =====

DeclareModule String
  
  Declare.s Between(String.s, StartString.s, EndString.s)
  Declare   Split(String.s, Array Result.s(1), Separator.s=" ")
  Declare.s Join(Array Result.s(1), Separator.s=" ")
  Declare   MulitSplit(String.s, Array Result.s(1), Separator.s=" ")
  Declare   Token(String.s, Array Result.s(1), Array Separators.s(1))
  Declare   Extract(String.s, Array Result.s(1), StartToken.s, EndToken.s)
  
EndDeclareModule

Module String
  
  Procedure   Split(String.s, Array Result.s(1), Separator.s=" ")
    ; by wilbert
    Define S.String, *S.Integer = @S
    Define.i aSize, i, Pos, sLen
    
    aSize = CountString(String, Separator)
    sLen  = Len(Separator)
    
    ReDim Result(aSize)
    
    *S\i = @String
    
    While i < aSize
      Pos = FindString(S\s, Separator)
      Result(i) = PeekS(*S\i, Pos - 1)
      *S\i + (Pos + sLen - 1) << #PB_Compiler_Unicode
      i + 1
    Wend
    
    Result(i) = S\s
    *S\i = 0
    
  EndProcedure

  Procedure.s Join(Array Result.s(1), Separator.s=" ")
    ; by wilbert
    Define.i aSize, i, sLen, tLen, *Buffer
    
    aSize = ArraySize(Result())
    sLen = Len(Separator)
    
    For i = 0 To aSize
      tLen + Len(Result(i)) + sLen
    Next
    
    tLen - sLen
    
    Dim Buffer.c(tLen)
    
    *Buffer = @Buffer()
    CopyMemoryString(Result(0), @*Buffer)
    For i = 1 To aSize
      CopyMemoryString(Separator)
      CopyMemoryString(Result(i))
    Next
    
    ProcedureReturn PeekS(@Buffer())
  EndProcedure
  
  Procedure   MulitSplit(String.s, Array Result.s(1), Separators.s=" ")
    Define.i c, sLen, aSize, Pos, EndPos, StartPos = 1
    
    NewList Token$()
    
    sLen = Len(String)
    
    While StartPos < sLen
      
      EndPos = sLen
      
      For c=1 To Len(Separators)
        
        If Mid(String, StartPos, 1) = Mid(Separators, c, 1)
          StartPos + 1
          Endpos = StartPos
          Break
        Else  
          Pos = FindString(String, Mid(Separators, c, 1), StartPos)
          If Pos And Pos < EndPos : EndPos = Pos : EndIf 
        EndIf  
  
      Next
  
      If EndPos <> StartPos
        If AddElement(Token$()) : Token$() = Mid(String, StartPos, EndPos - Startpos) : EndIf 
      EndIf
      
      StartPos = EndPos
    Wend
    
    aSize = ListSize(Token$()) - 1
    
    If aSize >= 0
    
      ReDim Result(aSize)
      
      c = 0
      
      ForEach Token$()
        Result(c) = Token$()
        c + 1
      Next 
      
    EndIf
    
  EndProcedure  
  
  Procedure   Token(String.s, Array Result.s(1), Array Separator.s(1))
    Define.i sLen, spSize, spLen, aSize
    Define.i i, Pos, EndPos, StartPos = 1

    NewList Token$()
    
    sLen   = Len(String)
    spSize = ArraySize(Separator())
    
    While StartPos < sLen
      
      spLen  = 0
      EndPos = sLen
      
      For i=0 To spSize
        
        If Mid(String, StartPos, Len(Separator(i))) = Separator(i)
          StartPos + Len(Separator(i))
          Endpos = StartPos
          Break
        Else  
          Pos = FindString(String, Separator(i), StartPos)
          If Pos And Pos < EndPos
            EndPos = Pos
            spLen  = Len(Separator(i))
          EndIf   
        EndIf
        
      Next

      If EndPos <> StartPos
        If AddElement(Token$()) : Token$() = Mid(String, StartPos, EndPos - Startpos) : EndIf 
      EndIf

      StartPos = EndPos + SpLen
    Wend
    
    aSize = ListSize(Token$()) - 1
    If aSize >= 0
    
      ReDim Result(aSize)
      
      c = 0
      
      ForEach Token$()
        Result(c) = Token$()
        c + 1
      Next 
      
    EndIf
    
  EndProcedure  
  
  Procedure   Extract(String.s, Array Result.s(1), StartToken.s, EndToken.s)
    Define.i sLen, aSize, Pos, EndPos, StartPos, Idx
    
    sLen  = Len(String)
    aSize = CountString(String, StartToken) - 1
    
    ReDim Result(aSize)
    
    Pos = 1
    StartPos = Pos
    
    While Pos
      
      Pos = FindString(String, StartToken, StartPos)
      If Pos 
        
        StartPos = Pos + Len(StartToken)
        
        EndPos = FindString(String, EndToken, StartPos)
        If StartPos < EndPos
          Result(Idx) = Mid(String, StartPos, EndPos - StartPos)
          Idx + 1
        EndIf  
        
        If EndPos : StartPos = Endpos + Len(EndToken) : EndIf
        
      EndIf  

    Wend  
    
  EndProcedure  
  
  Procedure.s Between(String.s, StartString.s, EndString.s)
    String = StringField(String, 2, StartString)
    ProcedureReturn StringField(String, 1, EndString)
  EndProcedure
  
EndModule  


;- ===== File =====

DeclareModule  File
  
  Declare.i Exists(File.s)
  
  Declare.i ValidPath(Path.s) 
  
EndDeclareModule

Module File
  
  Procedure.i Exists(File.s)    ; Does the file exist?
    
    If FileSize(File) >= 0
      ProcedureReturn #True
    EndIf
    
    ProcedureReturn #False
  EndProcedure
  
  Procedure.i ValidPath(Path.s) ; Is the path valid?
    
    If FileSize(Path) = -2
      ProcedureReturn #True
    EndIf  
    
    ProcedureReturn #False
  EndProcedure
  
  Procedure.s Directory(Path.s) ; Creates directory if it does not exist
    
    If Right(Path, 1) <> #PS$ : Path + #PS$ : EndIf
    
    If FileSize(Path) = -2
      ProcedureReturn Path
    Else  
      If CreateDirectory(Path)
        ProcedureReturn Path
      EndIf
    EndIf  

  EndProcedure  
  
EndModule  

;- ========  Module - Example ========

CompilerIf #PB_Compiler_IsMainFile

#Example = 0

; 0: String between
; 1: Split strings
; 2: Split with multiple separators
; 3: Token
; 4: Extrakt from token

  Select #Example
    Case 0 ;{ String between
    String$ = "<title>My String Between</title>"
    Debug String::Between(String$, "<title>", "</title>")
    ;}
    Case 1 ;{ Split & join strings
      
      Dim Result.s(0)
      
      Test$ = "This is a test string to see if split and join are working."
      
      String::Split(Test$, Result())
      
      For i = 0 To ArraySize(Result())
        Debug Str(i) + ": " + Result(i)
      Next
      
      Debug "---------------------"
      
      Result$ = String::Join(Result(), "_")
      
      Debug "=> " + Result$
      ;}
    Case 2 ;{ Split with multiple separators
      
      Dim Result.s(0)
      
      Test$ = "Command = DIR " + #DOUBLEQUOTE$ + "*.*" + #DOUBLEQUOTE$ + ", /s" + " " 
      
      String::MulitSplit(Test$, Result(), "=, ")
      
      For i = 0 To ArraySize(Result())
        Debug Str(i) + ": " + Result(i)
      Next
      ;}
    Case 3 ;{ Token
      
      Dim Result.s(0)
      Dim Separator.s(1)
      
      Separator(0) = "<b>"
      Separator(1) = "</b>"
      
      Test$ = "This is a <b>text</b> with <b>bold</b> words."
      
      String::Token(Test$, Result(), Separator())
      
      For i = 0 To ArraySize(Result())
        Debug Str(i) + ": " + Result(i)
      Next
      ;}
    Case 4 ;{ Extrakt from token
      
      Dim Result.s(0)
      
      Test$ = "This is a <b>text</b> with <b>bold</b> words."
      
      String::Extract(Test$, Result(), "<b>", "</b>")
      
      For i = 0 To ArraySize(Result())
        Debug Str(i) + ": " + Result(i)
      Next
      ;}
  EndSelect    

CompilerEndIf
SolveMyIssue_() - No QuickHelp available.
User avatar
mk-soft
Always Here
Always Here
Posts: 5398
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: StringBetween()

Post by mk-soft »

StringField is not an advantage, however, because a substring must be copied first.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: StringBetween()

Post by davido »

None-the-less useful.
Thank you to all contributors.
DE AA EB
Post Reply