Attribute VB_Name = "ex_Regex"
' ======= General functions for String regex manipulations ========
' Shared module version: 20210411
' Tested in: TestCommons
' Depends on:
' Required reference: VBScript_RegExp_55

' ====== API params =============
' sTarget - string to execute the regex on
' sPattern - the regular expression with at least 1 capture '()'
' nMatch - the index of the match you want to return (default: 0)
' nSubMatch - the index of the submatch you want to return (default: 0)

' Regex Execute returns collection of Match
' Match API: FirstIndex (0-indexed), Length, Value

' More info: https://vremya-ne-zhdet.ru/vba-excel/regulyarnyye-vyrazheniya/

Option Private Module
Option Explicit

Private Const REGEXP_SPECIAL$ = "[\?\.\$\^\(\)\[\]\{\}\\]"

Public Function RegexCountMatches(sTarget$, sPattern$) As String
'Returns the number of matches found for a given regex
  Dim regEx As New VBScript_RegExp_55.RegExp
  regEx.Pattern = sPattern
  regEx.Global = True
  Dim matches As Object
  If regEx.Test(sTarget) Then
    Set matches = regEx.Execute(sTarget)
    RegexCountMatches = matches.Count
    Exit Function
  End If
End Function

Function RegexExecute(sTarget$, sPattern$, Optional bOnlyFirstMatch As Boolean = False) As Object
'Executes a Regular Expression on a provided string and returns all matches
  Dim regEx As New VBScript_RegExp_55.RegExp
  regEx.Pattern = sPattern
  regEx.Global = Not (bOnlyFirstMatch)
  If regEx.Test(sTarget) Then
    Set RegexExecute = regEx.Execute(sTarget)
    Exit Function
  End If
End Function

Public Function RegexExecuteGet(sTarget$, sPattern$, Optional nMatch& = 0, Optional nSubMatch& = 0) As String
'Executes a Regular Expression on a provided string and returns a selected submatch
  Dim regEx As New VBScript_RegExp_55.RegExp
  regEx.Pattern = sPattern
  regEx.Global = nMatch <> 0 Or nSubMatch <> 0
  
  If regEx.Test(sTarget) Then
    Dim matches As Object:  Set matches = regEx.Execute(sTarget)
    
    On Error Resume Next
    RegexExecuteGet = matches(nMatch).SubMatches(nSubMatch)
  End If
End Function

Public Function RegexTest(sTarget$, sPattern$) As Boolean
' Test if sTarget matches regExp
  On Error GoTo EXIT_FUNC
  
  Dim regEx As New VBScript_RegExp_55.RegExp
  regEx.Pattern = sTarget
  regEx.Global = False
  RegexTest = regEx.Test(sPattern)
  
  On Error GoTo 0
EXIT_FUNC:
End Function

Public Function RegexMaskFrom(sTarget$) As String
' Creating regex mask from string - using \ to shield regular symbols
  RegexMaskFrom = RegexReplace(sTarget, "(" + REGEXP_SPECIAL + ")", "\$1")
End Function

Public Function RegexTextFromMask(mask$) As String
' Remove shielding from symbols
  RegexTextFromMask = RegexReplace(mask, "\\" + "(" + REGEXP_SPECIAL + ")", "$1")
End Function

Public Function RegexReplace(sTarget$, sPattern$, replaceStr$, Optional replaceLimit& = -1) As String
Attribute RegexReplace.VB_Description = "Replace a pattern within a string with the provided replacement string based on all captures of the specified regular expression"
Attribute RegexReplace.VB_ProcData.VB_Invoke_Func = " \n9"
'Replaces a string using Regular Expressions
'replaceStr - the string with which the sPattern pattern substrings are to be replaced with
'replaceLimit - by default unlimited (-1). Providing value will limit the number of performed replacements
  If replaceLimit = 0 Then
    RegexReplace = sTarget
    Exit Function
  End If

 Dim regEx As New VBScript_RegExp_55.RegExp
 regEx.Pattern = sPattern
 regEx.Global = IIf(replaceLimit = -1, True, False)
  If replaceLimit <> -1 And replaceLimit <> 1 Then
    RegexReplace = sTarget
    Dim i&
    For i = 1 To replaceLimit
      RegexReplace = RegexReplace(RegexReplace, sPattern, replaceStr, 1)
    Next i
  Else
    RegexReplace = regEx.Replace(sTarget, replaceStr)
  End If
End Function
