patriques
patriques

Reputation: 5201

parse a string with regexp

What is the best way if you want to read a input like this:

(1,13) { (22,446) (200,66) (77,103) } 
(779,22) {  } // this is also possible, but always (X,X) in the beginning

I would like to use regular expressions for doing it. But there is little info on usage of reqexp when parsing a string with more than only numbers. Currently im trying something similar with sscanf (from the c-library):

string data;
getline(in, data); // format: (X,X) { (Y,Y)* } 
stringstream ss(data);
string point, tmp;
ss >> point; // (X,X)
// (X,X) the reason for three is that they could be more than one digit.
sscanf(point.c_str(), "(%3d,%3d)", &midx, &midy); 

int x, y;
while(ss >> tmp) // { (Y,Y) ... (Y,Y) }
{
    if(tmp.size() == 5)
    {
        sscanf(tmp.c_str(), "(%3d,%3d)", &x, &y);
        cout << "X: " << x << " Y: " << y << endl;  
    }
}

The problem is that this does not work, as soon as there is more than one digit sscanf does not read the numbers. So is this the best way to go, or is there a better solution with regexp? I don´t want to use boost or something like that as this is part of a school assignment.

Upvotes: 2

Views: 173

Answers (2)

Dimitrios Bouzas
Dimitrios Bouzas

Reputation: 42889

Maybe the following piece of code matches your requirements:

#include <iostream>
#include <string>
#include <regex>

int main()
{
  std::smatch m;
  std::string str("(1,13) { (22,446) (200,66) (77,103) }");
  std::string regexstring = "(\\(\\s*\\d+\\s*,\\s*\\d+\\s*\\))\\s*(\\{)(\\s*\\(\\s*\\d+\\s*,\\s*\\d+\\s*\\)\\s*)*\\s*(\\})";
  if (std::regex_match(str, m, std::regex(regexstring))) {
    std::cout << "string literal matched" << std::endl;
    std::cout << "matches:" << std::endl;
    for (std::smatch::iterator it = m.begin(); it != m.end(); ++it) {
      std::cout << *it << std::endl;
    }
  }

  return 0;
}

Output:

enter image description here

Upvotes: 1

Ethan Lynn
Ethan Lynn

Reputation: 1009

Assuming you're using C++11, you could use something like: std::regex pattern(r"\((\d+),(\d+)\)\s*\{(\s*\(\d+,\d+\))+\s*\}") (Disclaimer: This hasn't been tested), and then use it like so:

std::smatch match;
while (ss >> tmp) {
   if (std::regex_match(tmp, match, pattern)) {
      // match[0] contains the first number as a string
      // match[1] contains the second number as a string
      // match[2] contains the list of points
   }
}

Upvotes: 1

Related Questions