0

my question is about this: I have some problems with my logic. I already detect when it have a parenthesis, but now I need to find numbers and know how many times they repeat in the txt file. This is my txt file:

(Visual basic)
(Llorente)
(Porto, 2008)
(Sommerville, 2010)
References
Visual Basic. (s.f.). Navarra.
Llorente, P.B. (s.f.). Fortran.
Porto, J.P. (2008)
Sommerville, I. (2010). Software Engineering. Unite Kingdom: Pearson.

The result should be: year : 2008 - 2 times, year : 2010 - 2 times, etc. PD: thanks I'm very noob.

#include <regex>
#include <iostream>
#include <fstream>
#include <map>
//33
int main()
{
    std::ifstream readStream("references.txt");
    std::map<int, int> cMap; 
    std::string input;
    std::regex reg(R"(\([a-zA-Z\s]*,?\s*([0-9]+)\))");
    std::regex inte("(\\+|-)?[[:digit:]]+");

    ///333
    while (std::getline(readStream, input)) {
            std::match_results < std::string::const_iterator > m;
    if ((std::regex_search(input, m, reg)) ) {
        int year = std::stoi(m[1]); 
        auto value = cMap.find(year);
        if (value != cMap.end()) { 
            cMap[value->first] = value->second + 1;
        } else {
            cMap[year] = 1; 
        }
    }



}
//33
for (auto x : cMap) { 
    std::cout << "year " << x.first << " is - " << x.second << " times." << std::endl;
}
//3
return 0;
}
Murata
  • 3
  • 2
  • Sounds like a perfect job for a [regex](https://en.cppreference.com/w/cpp/regex) (as does finding the parentheses in the first place) – john Aug 05 '18 at 05:38
  • I use g++ I can't use regex. – Murata Aug 05 '18 at 06:46
  • Huh? g++ supports regex, they're part of C++. – john Aug 05 '18 at 07:42
  • @john "I had a problem and chose regex to solve it. Now, I had two problems." ;-) – Scheff's Cat Aug 05 '18 at 08:48
  • To find a number in a string, you could iterate `c` through characters until you find a digit (`c >= '0' && c <= '9'`). Then, you iterate as long as you find digits. Or, even simpler: use `strtol()`. (It tells you the number and pointer to stop char as well.) – Scheff's Cat Aug 05 '18 at 08:53
  • For more complex analysis, you could make a parser. I once wrote a demo for [SO: How to rearrange a string equation?](https://stackoverflow.com/a/50021308/7478597) – Scheff's Cat Aug 05 '18 at 09:01
  • Please, don't provide textual info as image. Please, copy/paste it into question (and format it as code in case). – Scheff's Cat Aug 05 '18 at 09:14

2 Answers2

1

You can use std::regex_search method to match the lines. But remember to include #include <regex> at the top of the file.

#include <regex>
#include <iostream>
#include <fstream>
#include <map>


int main()
{
    std::ifstream readStream("path/to/your/Example.txt");
    std::map<int, int> countMap; // Map containing (year, count) value pairs.
    std::string in;
    std::regex reg(R"(\([a-zA-Z\s]*,?\s*([0-9]+)\))"); // For the regex: \([a-zA-Z\s]*,?\s*([0-9]+)\)

    while (std::getline(readStream, in)) {
        std::match_results < std::string::const_iterator > m;
        if (std::regex_search(in, m, reg)) { // If the current line matches our regex pattern.
            int year = std::stoi(m[1]); // The second element of the array contains our string representing the year.

            auto val = countMap.find(year);
            if (val != countMap.end()) { // If the year is already in the countMap we want to increment it.
                countMap[val->first] = val->second + 1;
            } else {
                countMap[year] = 1; // year doesn't exist in the countMap, it is the first time.
            }
        }
    }

    for (auto x : countMap) { // x is of type std::pair<int, int> which is our (year, count) value pair
        std::cout << "year " << x.first << " is - " << x.second << " times." << std::endl;
    }

    return 0;
}
Mohit
  • 1,055
  • 9
  • 24
  • Thanks, this is very helpful, I have a question, when try to add one more regular expression to the if statement but when i add another std::stoi I got and exception . – Murata Aug 05 '18 at 22:12
0

For the task of OP, a simple loop can do the job which iterates through all characters of string. Thereby, two states are managed:

  • open ... true after '(' and before ')', otherwise false
  • number ... true when digits have been found while open was true.

While number is true digits are collected and combined to an int. If a non-digit is found while number is true this is the end of number and the value is stored.

The check for number can be done at end of line as well. In this specific case, it would mean a syntax error because it means the closing parenthesis ()) is missing. (The OP didn't claim how to handle this.)

My sample code:

#include <iostream>
#include <sstream>
#include <vector>
#include <map>

std::vector<int> parseLine(const std::string &text)
{
  bool open = false, number = false;
  std::vector<int> values; int value = 0;
  for (char c : text) {
    switch (c) {
      case '(': open = true; break;
      case ')': open = false;
      default:
        if (open && c >= '0' && c <= '9') {
          number = true;
          (value *= 10) += (c - '0'); // value = 10 * value + (c - '0')
        } else if (number) {
          values.push_back(value);
          value = 0; number = false;
        }
    }
  }
  if (number) {
    values.push_back(value);
    std::cerr << "ERROR: Missing ')' at line end!\n";
  }
  return values;
}

const std::string text =
"(Visual basic)\n"
"(Llorente)\n"
"(Porto, 2008)\n"
"(Sommerville, 2010)\n"
"References\n"
"Visual Basic. (s.f.). Navarra.\n"
"Llorente, P.B. (s.f.). Fortran.\n"
"Porto, J.P. (2008)\n"
"Sommerville, I. (2010). Software Engineering. Unite Kingdom: Pearson.\n";

int main()
{
  // open file
  std::istringstream in(text);
  // parse/process file line by line
  std::map<int, int> histo;
  for (std::string line; std::getline(in, line);) {
    const std::vector<int> values = parseLine(line);
    // count occurrences of values
    for (int value : values) ++histo[value];
  }
  // report
  std::cout << "Report:\n";
  for (const std::pair<int, int> &entry : histo) {
    std::cout << entry.first << ": " << entry.second << '\n';
  }
  // done
  return 0;
}

Output:

Report:
2008: 2
2010: 2

Live Demo on coliru

Scheff's Cat
  • 16,517
  • 5
  • 25
  • 45