title: How to match escaped group signs {&date:dd.\{mm\}.yyyy} but not {&date:dd.{mm}.yyyy} with vba and regex
body: <p>I'm trying to create a pattern for finding placeholders within a string to be able to replace them with variables later. I'm stuck on a problem to find all these placeholders within a string according to my requirement.</p>
  
  <p>I already found this post, but it only helped a little:
  <a href="https://stackoverflow.com/questions/45839814/regex-match-but-not">Regex match ; but not \;</a></p>
  
  <p>Placeholders will look like this</p>
  
  <pre><code>{&amp;var} --&gt; Variable stored in a dictionary --&gt; dict("var")
  {$prop} --&gt; Property of a class cls.prop read by CallByName and PropGet
  {#const} --&gt; Some constant values by name from a function
  </code></pre>
  
  <p>Generally I have this pattern and it works well</p>
  
  <pre><code>    Dim RegEx As Object
      Set RegEx = CreateObject("VBScript.RegExp")
      RegEx.pattern = "\{([#\$&amp;])([\w\.]+)\}"
  </code></pre>
  
  <p>For example I have this string:
  "Value of foo is '{&amp;var}' and bar is '{$prop}'"
  I get 2 matches as expected</p>
  
  <ol>
  <li>(&amp;)(var)</li>
  <li>($)(prop)</li>
  </ol>
  
  <p>I also want to add a formating part like in .Net to this expression.</p>
  
  <pre><code>    String.Format("This is a date: {0:dd.mm.yyyy}", DateTime.Now());
      // This is a date: 05.07.2019
      String.Format("This is a date, too: {0:dd.(mm).yyyy}", DateTime.Now());
      // This is a date, too: 05.(07).2019
  </code></pre>
  
  <p>I extended the RegEx to get that optional formatting string</p>
  
  <pre><code>    Dim RegEx As Object
      Set RegEx = CreateObject("VBScript.RegExp")
      RegEx.pattern = "\{([#\$&amp;])([\w\.]+):{0,1}([^\}]*)\}"
      RegEx.Execute("Value of foo is '{&amp;var:DD.MM.YYYY}' and bar is '{$prop}'")
  </code></pre>
  
  <p>I get 2 matches as expected</p>
  
  <ol>
  <li>(&amp;)(var)(DD.MM.YYYY)</li>
  <li>($)(prop)()</li>
  </ol>
  
  <p>At this point I noticed I have to take care for escapet "{" and "}", because maybe I want to have some brackets within the formattet result.</p>
  
  <p>This does not work properly, because my pattern stops after "...{MM"</p>
  
  <pre><code>RegEx.Execute("Value of foo is '{&amp;var:DD.{MM}.YYYY}' and bar is '{$prop}'")
  </code></pre>
  
  <p>It would be okay to add escape signs to the text before checking the regex:</p>
  
  <pre><code>RegEx.Execute("Value of foo is '{&amp;var:DD.\{MM\}.YYYY}' and bar is '{$prop}'")
  </code></pre>
  
  <p>But how can I correctly add the negative lookbehind?</p>
  
  <p>And second: How does this also works for variables, that should not be resolved, even if they have the correct syntax bus the outer bracket is escaped?</p>
  
  <pre><code>RegEx.Execute("This should not match '\{&amp;var:DD.\{MM\}.YYYY\}' but this one '{&amp;var:DD.\{MM\}.YYYY}'")
  </code></pre>
  
  <p>I hope my question is not confusing and someone can help me</p>
  
  <p><strong>Update 05.07.19 at 12:50</strong>
  After the great help of @wiktor-stribiżew the result is completed.</p>
  
  <p>As requested i provide some example code:</p>
  
  <pre><code>    Sub testRegEx()
          Debug.Print FillVariablesInText(Nothing, "Date\\\\{$var01:DD.\{MM\}.YYYY}\\\\ Var:\{$nomatch\}{$var02} Double: {#const}{$var01} rest of string")
      End Sub
  
      Function FillVariablesInText(ByRef dict As Dictionary, ByVal txt As String) As String
          Const c_varPattern As String = "(?:(?:^|[^\\\n])(?:\\{2})*)\{([#&amp;\$])([\w.]+)(?:\:([^}\\]*(?:\\.[^\}\\]*)*))?(?=\})"
  
          Dim part As String
          Dim snippets As New Collection
          Dim allMatches, m
          Dim i As Long, j  As Long, x As Long, n As Long
  
          ' Create a RegEx object and execute pattern
          Dim RegEx As Object
          Set RegEx = CreateObject("VBScript.RegExp")
          RegEx.pattern = c_varPattern
          RegEx.MultiLine = True
          RegEx.Global = True
          Set allMatches = RegEx.Execute(txt)
  
          ' Start at position 1 of txt
          j = 1
          n = 0
          For Each m In allMatches
              n = n + 1
              Debug.Print "(" &amp; n &amp; "):" &amp; m.value
              Debug.Print "    [0] = " &amp; m.SubMatches(0) ' Type [&amp;$#]
              Debug.Print "    [1] = " &amp; m.SubMatches(1) ' Name
              Debug.Print "    [2] = " &amp; m.SubMatches(2) ' Format
              part = "{" &amp; m.SubMatches(0)
              ' Get offset for pre-match-string
              x = 1 ' Index to Postion at least +1
              Do While Mid(m.value, x, 2) &lt;&gt; part
                  x = x + 1
              Loop
              ' Postition in txt
              i = m.FirstIndex + x
              ' Anything to add to result?
              If i &lt;&gt; j Then
                  snippets.Add Mid(txt, j, i - j)
              End If
              ' Next start postition (not Index!) + 1 for lookahead-positive "}"
              j = m.FirstIndex + m.Length + 2
  
              ' Here comes a function get a actual value
              ' e.g.: snippets.Add dict(m.SubMatches(1))
              ' or  : snippets.Add Format(dict(m.SubMatches(1)), m.SubMatches(2))
              snippets.Add "&lt;&lt;" &amp; m.SubMatches(0) &amp; m.SubMatches(1) &amp; "&gt;&gt;"
          Next m
          ' Any text at the end?
          If j &lt; Len(txt) Then
              snippets.Add Mid(txt, j)
          End If
  
          ' Join snippets
          For i = 1 To snippets.Count
              FillVariablesInText = FillVariablesInText &amp; snippets(i)
          Next
      End Function
  </code></pre>
  
  <p>The function testRegEx gives me this result and debug print:</p>
  
  <pre><code>(1):e\\\\{$var01:DD.\{MM\}.YYYY(2):}{$var02
      [0] = $
      [1] = var02
      [2] = 
  (1):e\\\\{$var01:DD.\{MM\}.YYYY
      [0] = $
      [1] = var01
      [2] = DD.\{MM\}.YYYY
  (2):}{$var02
      [0] = $
      [1] = var02
      [2] = 
  (3): {#const
      [0] = #
      [1] = const
      [2] = 
  (4):}{$var01
      [0] = $
      [1] = var01
      [2] = 
  Date\\\\&lt;&lt;$var01&gt;&gt;\\\\ Var:\{$nomatch\}&lt;&lt;$var02&gt;&gt; Double: &lt;&lt;#const&gt;&gt;&lt;&lt;$var01&gt;&gt; rest of string
  </code></pre>