Rahul
Rahul

Reputation: 11560

Find all strings within a string

I get StrTxt as html string by http request response text. I want to find all occurrences of '"string"' in the StrTxt.

Something like this.

for each string in StrTxt
StrTxt = "all matched strings from StrTxt"
do something StrTxt.

Edit This is tagged as possible duplicate but it's not. How to loop through each word in a word document - VBA Macro explains how to find string in document and not string.

It is just simple. How to find all strings withing strings? Isn't my title explains everything?

Edit 2

From answer of Ansgar Wiechers I tried following.

Do
i = InStr(strtxt, "startstring")
      If i > 0 Then
        strtxt = Mid(strtxt, i, Len(strtxt) - i)
        i = InStr(InStr(strtxt, "midstring") + 1, strtxt, "endstring")
        If i > 0 Then
         strtxt = Left(strtxt, i + Len(endstring)) ' I am using i+4 as I know the length
        WScript.Echo strtxt
        End If
      End If
Loop While i > 0

It gives only one occurences. How to loop correctly?

Upvotes: 2

Views: 16879

Answers (3)

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200473

If you want to use InStr to search a string for all occurrences of a particular substring you need to call the function repeatedly, starting each new search (at least) one character after the last match.

response = "..."  'your HTTP response string
srch     = "..."  'the string you want to find in the response

start = 1
Do
  pos = InStr(start, response, srch, vbTextCompare)
  If pos > 0 Then
    start = pos + 1  'alternatively: start = pos + Len(srch)
    WScript.Echo pos
    WScript.Echo Mid(response, pos, Len(srch))
  End If
Loop While pos > 0

If you want the comparison to be case-sensitive replace vbTextCompare with vbBinaryCompare.


Edit: For finding patterns that start with some string, contain another, and end with a third one it's probably best to use a regular expression. @TylerStandishMan already showed the basic principle in his answer, but there are some things to observe in your scenario.

response = "..."  'your HTTP response string

startTerm = "startstring"
midTerm   = "midstring"
endTerm   = "endstring"

Set re = New RegExp
re.Pattern    = startTerm & "[\s\S]*?" & midTerm & "[\s\S]*?" & endTerm
re.Global     = True
re.IgnoreCase = True  'if required

For Each m In re.Execute(response)
  WScript.Echo m
Next

Some characters in a regular expression have a special meanings (e.g. . matches any character except newlines), so you need to make sure that any such character in your start, mid and end terms is properly escaped (e.g. use \. for matching a literal dot). In case the substring you want to match spans more than one line you need those parts of the expression that match arbitrary text between your search terms to include newline characters (e.g. [\s\S] to match any whitespace or non-whitespace character). You may also want to make the match non-greedy, otherwise you'd get a single match from the first occurrence of startTerm to the last occurrence of endTerm. That's what the modifier *? is for.

Upvotes: 7

Hackoo
Hackoo

Reputation: 18847

Try this commented example using a dynamic array and InStr function :

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Find a string in a sentence
'Recherche d'une chaine de caractère dans une phrase
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Instruction Option Explicit: Force explicit declaration of all variables in a script
'Instruction Option Explicit: Force la déclaration explicite de toutes les variables dans un script
Option Explicit 
Dim Texte,sChaine
Texte = "This is my string. {This is another string.} How do I go about searching through this?" 
sChaine = "this"   'chaine recherchée
'Instruction Dim: Declares variables and allocates storage space
'Instruction Dim: Déclare des variables et alloue l'espace de stockage
Dim aPos() , iPos
'ReDim Statement: Declares the dynamic array of variables and attribute or
'Reallocates storage space at the procedure
'Table where positions are stored
'Instruction ReDim: Déclare les variables de tableau dynamique et attribue ou 
'réattribue l'espace de stockage au niveau de la procédure
'Tableau ou sont stockées les positions
ReDim aPos(0)  
'InStr Function: Returns the position of the first occurrence of a string
'In the interior of another
'Fonction InStr: Renvoie la position de la première occurrence d'une chaîne 
'à l'intérieur d'une autre
iPos = InStr(1, Texte, sChaine, vbTextCompare)  
'Instruction While ... Wend: Run a set of instructions as long as a given condition is True
'Instruction While...Wend: Exécute une série d'instructions tant qu'une condition donnée est True
    While iPos <> 0 
'UBound Function: Returns the largest available subscript for the indicated dimension of an array   
'Fonction UBound: Renvoie le plus grand indice disponible pour la dimension indiquée d'un tableau
        ReDim Preserve aPos(UBound(aPos) + 1) 
        aPos(UBound(aPos)) = iPos 
        iPos = InStr(iPos + 1, Texte, sChaine, vbTextCompare) 
    Wend 
'If ... Then ... Else Instruction: Executes a group of statements subject to a condition,
'In dependence of the value of an expression
'Instruction If...Then...Else: Exécute un groupe d'instructions soumises à une condition, 
'en fonction de la valeur d'une expression
    If UBound(aPos) > 0 Then 
        Dim i , Resultat 
        Resultat = "Occurrence """ & sChaine & """ found " & UBound(aPos) & " times " & _
                    "in the phrase" & vbCrLf & vbCrLf & """" & Texte & """" & vbCrLf & vbCrLf & _                   
                    "L'occurrence """ & sChaine & """ a été trouvée " & UBound(aPos) & " fois " &_
                   "dans l'expression " & vbCrLf & vbCrLf & """" & Texte & """" & vbCrLf 
'Instruction For ... Next: Repeats a group of statements a specified number of times
'CStr Function: Returns an expression that has been converted to a String subtype Variant
'Len Function: Returns the number of characters in a string
'Instruction For...Next: Répète un groupe d'instructions un nombre spécifié de fois
'Fonction CStr: Renvoie une expression qui a été convertie en un Variant de sous-type String
'Fonction Len: Renvoie le nombre de caractères contenus dans une chaîne
        For i = 1 To UBound(aPos) 
            Resultat = Resultat & vbCrLf & "Postion: " & CStr(aPos(i)) & "," & CStr(aPos(i)) + Len(sChaine)
        Next  
    Else     
        Resultat = "L'occurrence """ & sChaine & """ n'a pas été trouvée dans l'expression " &vbCrLf&vbCrLf&_
        """" & Texte & """"
    End If 
Wscript.echo Resultat

Upvotes: 1

Tyler StandishMan
Tyler StandishMan

Reputation: 459

By using Replace and Split, this was easily accomplished.

Option Explicit

Public Sub StringInString()

    Dim myString As String: myString = "This is my string. {This is another string.} How do I go about searching through this?"
    Dim findString As String: findString = "this"
    Dim var As Variant, mySplit As Variant
    Dim matchCount As Integer: matchCount = 0

    '    Remove any characters that aren't pure text, but leave spaces so we can split on those.
    Dim removeChars: removeChars = Array(".", ",", "/", "\", "|", "{", "}", "[", "]", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "-", "+", "=", ":", ";", """", "'", "<", ">", "?", "`", "~")

    For Each var In removeChars
        myString = Replace(myString, var, vbNullString)
    Next

    mySplit = Split(myString, " ")

    For Each var In mySplit
        If (LCase(findString) = LCase(var)) Then matchCount = matchCount + 1
    Next

End Sub

I don't quite know what it is you're expecting as your output, so modify as needed.

EDIT:

Even simpler solution, using Regular Expressions (required reference to Micrsoft VBScript Regular Expressions 5.5):

Public Sub StringInStringRegex()

    Dim myString As String: myString = "This is my string. {This is another string.} How do I go about searching through this?"

    Dim reg As New RegExp
    reg.Pattern = "(this)"
    reg.Global = True
    reg.IgnoreCase = True
    reg.MultiLine = True

    Dim Matches As MatchCollection
    Set Matches = reg.Execute(myString)

    Dim matchCount As Integer: matchCount = Matches.Count

End Sub

Sources: How to use Regular Expressions (Regex) in Microsoft Excel both in-cell and loops and Pattern match count in excel (regex & vba)

Upvotes: 2

Related Questions