Problem Using regex

Why am I getting a bad line: 1 when I run the program? The regex row expression regex row {R"(^[\w ]+( \d+)( \d+)( \d+)$)"}; appears to be correct. There is one tab to the first \d+ and two tabs to the second and third \d+. I do not know why it does not work.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
 //	C23 Matching.cpp
#include <regex>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;

struct bad_from_string : bad_cast {
	const char* what() const override
	{
		return "bad cast from string";
	}
};

template<typename T> T from_string(const string& s)
{
	istringstream is{ s };
	T t;
	if (!(is >> t)) throw bad_from_string{};
	return t;

}

int main()
{
	ifstream in{ "table.txt" };
	if (!in) cerr << "no input file\n";

	string line;					//	input buffer
	int lineno = 0;

	regex header {R"(^[\w ]+(	[\w ]+)*$)"};
	regex row {R"(^[\w ]+(	\d+)(		 \d+)(		\d+)$)"};

	if (getline(in, line)) {
		smatch matches;
		if (!regex_match(line, matches, header)) {
			cerr << "no header\n";
		}
	}


	// column totals
	int boys = 0;
	int girls = 0; 

	while (getline(in, line)) {
		++lineno;
		smatch matches;
		if (!regex_match(line, matches, row))
			cerr << "bad line: " << lineno << '\n';

		if (in.eof()) cout << "at eof\n";

		// check row:
		int curr_boy = from_string<int>(matches[1]);
		int curr_girl = from_string<int>(matches[2]);
		int curr_total = from_string<int>(matches[3]);
		if (curr_boy + curr_girl != curr_total) cerr << "bad row sum \n";
		
		if (matches[1] == "Alle") {
			if (curr_boy != boys) cerr << "boys don't add up\n";
			if (curr_girl != girls) cerr << "girls don't add up\n";
			if (!(in >> ws).eof()) cerr << "characters after total line";
			return 0;
		}

		// update totals
		boys += curr_boy;
		girls += curr_girl;
	}

	cerr << "didn't find total line";
}


Here is my table.txt file. There are tabs between words and numbers. Antal Drenge is Danish for boys, and Antal Piger is Danish for girls. Elever Ialt is the row total of boys and girls.
1
2
3
4
5
6
7
8
9
10
KLASS	ANTAL DRENGE	ANTAL PIGER	ELEVER IALT
0A 	12		11		23
1A	7		8		15
1B	4		11		15
2A	10		13		23
3A	10		12		22
4A	7		7		14
4B	10		5		15
5A	19		8		27
Alle	79		75		154
Last edited on
I heard www.pastebin.com is a nice place to post code on.

You've gotta tell us what your question or problem is. Or tell us that you are just sharing this code.
Last edited on
Two observations:

Try using \t+ for tabs.
You are not capturing the column KLASS so line 62 will never evaluate to true.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <string>
#include <regex>
#include <sstream>

struct data { int nb ; int ng ; int nt ; };

bool parse( std::string line, data& d )
{
    static const std::regex re( R"(^\s*\w+\s*(\d+)\s+(\d+)\s+(\d+)\s*$)" ) ;

    std::smatch match ;
    if( std::regex_match( line, match, re ) )
    {
        d = { std::stoi( match[1].str() ), std::stoi( match[2].str() ), std::stoi( match[3].str() ) } ;
        return true ;
    }
    
    d = {} ;
    return false ;
}

int main ()
{
    for( std::string line : { "0A 12    11 23", "0A     12 11 19", "0A 	12 0x11 23" } )
    {
        data d ;
        if( parse( line, d ) )
        {
            std::cout << d.nb << ' ' << d.ng << ' ' << d.nt ;
            if( d.nt == (d.nb+d.ng) ) std::cout << " (ok)\n" ;
            else std::cout << " (incorrect total)\n" ;
        }

        else std::cout << "bad line '" << line << "'\n" ;
    }
}

http://coliru.stacked-crooked.com/a/fc64750c80112959
norm b,

I tried the \t+ and it worked.

JLBorges,

1. An interesting for statement. Where do you find the syntax for this type of for statement?
2. What is the purpose of line 19, d = {};? It appears that it is not needed.

Now that the program reads the rows, how do you get line 62 in my program to execute?

> Where do you find the syntax for this type of for statement?

http://www.stroustrup.com/C++11FAQ.html#for


> What is the purpose of line 19, d = {};?

It clears the contents of d (sets integers to zero, strings to empty strings etc.)
Here, the empty braced-init-list {} denotes a value-initialised anonymous temporary object of type data.


> how do you get line 62 in my program to execute?

normb > You are not capturing the column KLASS so line 62 will never evaluate to true.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <string>
#include <regex>
#include <sstream>

struct data { std::string klass /* added */ ; int nb ; int ng ; int nt ; };

bool parse( std::string line, data& d )
{
    //static const std::regex re( R"(^\s*\w+\s*(\d+)\s+(\d+)\s+(\d+)\s*$)" ) ;
    static const std::regex re( R"(^\s*(\w+)\s*(\d+)\s+(\d+)\s+(\d+)\s*$)" ) ; // add a capture group for KLASS

    std::smatch match ;
    if( std::regex_match( line, match, re ) )
    {
        d = { match[1].str(), std::stoi( match[2].str() ), std::stoi( match[3].str() ), std::stoi( match[4].str() ) } ;
        return true ;
    }

    d = {} ;
    return false ;
}

int main ()
{
    int nb_computed = 0 ;
    int ng_computed = 0 ;

    for( std::string line : { "0A 12    11 23", "0B     30 45 75 ", "0C 15 12 27",  "Alle     58 68 122" } )
    {
        data d ;
        if( parse( line, d ) )
        {
            if( d.klass == "Alle" )
            {
                std::cout << "--------------\n" << d.nb << ' ' << d.ng << ' ' << d.nt << " (Alle)\n" ;
                if( nb_computed != d.nb ) std::cout << "boys don't add up\n" ;
                if( ng_computed != d.ng ) std::cout << "girls don't add up\n" ;
                if( d.nt != (d.nb+d.ng) ) std::cout << "total does not add up\n" ;
                break ;
            }

            else
            {
                std::cout << d.nb << ' ' << d.ng << ' ' << d.nt ;
                if( d.nt == (d.nb+d.ng) ) std::cout << " (ok)\n" ;
                else std::cout << " (incorrect total)\n" ;

                nb_computed += d.nb ;
                ng_computed += d.ng ;
            }
        }

        else std::cout << "bad line '" << line << "'\n" ;
    }
}

http://coliru.stacked-crooked.com/a/26e76fefa02ee9b7

Note: std::stoi() will throw if the value is out of range; you may want to wrap that part within a try block.
JLBorges,

Is there a way to extract the substring, "Alle", out from matches[0]?
> Is there a way to extract the substring, "Alle", out from matches[0]?

match[0].str().find( "Alle" )

or simply: line.find( "Alle" ) - if there is a match, the entire sequence is matched, and line == match[0].str()
JLBorges,

Thank you for all your help. I changed line 62 in my code to the following:
if (matches[0].str().find("Alle") == 0) {, and it worked.
Topic archived. No new replies allowed.