Question about Regex library issue

Posted by Tarcas on Mon 11 Sep 2017 01:00 AM — 4 posts, 18,995 views.

#0
Hi Nick,
I'd like to start by thanking you profusely for creating the regex library. I see that this was some years ago, but it looks like it should solve my problem nicely.

Unfortunately, I have run into an issue. Probably my fault, but I can't figure out how. I have an expression that I'm searching for:

char result=ms.Match ("([rw])(%d+)(%w)");

and I'm returning the list of captures per your example code:

      if (result == REGEXP_MATCHED)
        {
           Serial.println("Matched.");
           for (int j = 0; j < 3; j++)
          {
            Serial.print ("Capture number: ");
            Serial.println (j, DEC);
            Serial.print ("Text: '");
            Serial.print (ms.GetCapture (buf, j));
            Serial.println ("'");
          }
          // matching offsets in ms.capture
        }

It works great with one small issue that I'm trying to solve. The %d+ in the middle captures (or at least prints) nothing if the matched expression is at the beginning of the line. If I insert a space or one or more random characters before the text that I want matched, it works fine and I get my digits.

I've tried changing the expression to match the beginning of the line, and it didn't help my issue. I've also tried changing the %d+ to a %w+ thinking that maybe digits caused it, but there was no change (except that it would match on letters as well as digits, of course.)
Everything I've done does correctly print the leading "r" or "w" and the trailing alphanumeric character. Just not the digits in the middle if the string is at the beginning of the line.

Short of prefixing an extra character every time I send a code to match, I'm not sure where to go with this. Is this some gotcha with captures that I've just never heard of?

example output:

Attempting match on: r55t
r55t
Matched.
Capture number: 0
Text: 'r'
Capture number: 1
Text: ''
Capture number: 2
Text: 't'
Attempting match on:  r55t
 r55t
Matched.
Capture number: 0
Text: 'r'
Capture number: 1
Text: '55'
Capture number: 2
Text: 't'

I would welcome your insights.
Amended on Mon 11 Sep 2017 01:02 AM by Tarcas
Australia Forum Administrator #1
It would have helped to provide the full code. I could reproduce your issue with this code:


#include <Regexp.h>

void setup ()
{
  Serial.begin (115200);
  Serial.println ();

  // match state object
  MatchState ms;

  // what we are searching (the target)
  char buf [10] = "r55t";
  ms.Target (buf);  // set its address
  Serial.println (buf);

  char result=ms.Match ("([rw])(%d+)(%w)");
  
 if (result == REGEXP_MATCHED)
    {
       Serial.println("Matched.");
       for (int j = 0; j < 3; j++)
      {
        Serial.print ("Capture number: ");
        Serial.println (j, DEC);
        Serial.print ("Text: '");
        Serial.print (ms.GetCapture (buf, j));
        Serial.println ("'");
      }
      // matching offsets in ms.capture
    }
  else
    Serial.println ("No match");
        
    
}  // end of setup  

void loop () {}


However what you are doing wrongly here (assuming you did something similar) is to use "buf" for two different purposes.

According to the documentation:

Quote:

After a successful match, this copies the matching string from the target buffer to another memory location, with a null-terminator.


(My emphasis)

However by using "buf" here for the source text, and also for the location to copy the string to, you are corrupting the source text with the capture.

If you use a different buffer for the capture text, it works:



#include <Regexp.h>

void setup ()
{
  Serial.begin (115200);
  Serial.println ();

  // match state object
  MatchState ms;

  // what we are searching (the target)
  char buf [10] = "r55t";
  ms.Target (buf);  // set its address
  Serial.println (buf);

  char result=ms.Match ("([rw])(%d+)(%w)");
  
 if (result == REGEXP_MATCHED)
    {
       Serial.println("Matched.");
       for (int j = 0; j < 3; j++)
      {
        Serial.print ("Capture number: ");
        Serial.println (j, DEC);
        Serial.print ("Text: '");
        char captureBuf [10];
        Serial.print (ms.GetCapture (captureBuf, j));
        Serial.println ("'");
      }
      // matching offsets in ms.capture
    }
  else
    Serial.println ("No match");
        
    
}  // end of setup  

void loop () {}
Amended on Sat 16 Sep 2017 06:42 AM by Nick Gammon
#2
Thank you very much! That is exactly what I did. Now I'm confused about why I was able to get the 3rd capture if the first capture overwrote the data and prevented the 2nd from coming through.
Australia Forum Administrator #3
Well, the buffer would have had in it:


r55t


After getting capture "r" the buffer would now have:


r(null)5t


When attempting to get the second capture (offset 1) it would hit the 0x00 byte written there when getting the "r" and found an empty string.

However when getting the "t" we are past the corrupted part, so the "t" is still there.