C ++ getline - извлечение подстроки с помощью регулярных выражений - PullRequest
0 голосов
/ 22 февраля 2020

У меня есть файл с таким содержимым -

Random text
+-------------------+------+-------+-----------+-------+
|     Data          |   A  |   B   |     C     |   D   |
+-------------------+------+-------+-----------+-------+
|   Data 1          | 1403 |     0 |      2520 | 55.67 |
|   Data 2          | 1365 |     2 |      2520 | 54.17 |
|   Data 3          |    1 |     3 |      1234 | 43.12 |
Some more random text

Я хочу извлечь значение столбца D строки Data 1, т.е. я хочу извлечь значение 55.67 из примера над. Я разбираю этот файл построчно, используя getline -

while(getline(inputFile1,line)) {
    if(line.find("|  Data 1") != string::npos) {
        subString = //extract the desired value
}

Как извлечь из строки нужную подстроку. Есть ли способ, используя boost :: regex, чтобы я мог извлечь эту подстроку?

Ответы [ 2 ]

2 голосов
/ 22 февраля 2020

Хотя regex может иметь свое применение, это, вероятно, излишне для этого.

Включите функцию trim и:

char delim;
std::string line, data;
int a, b, c;
double d;

while(std::getline(inputFile1, line)) {
    std::istringstream is(line);
    if( std::getline(is >> delim, data, '|') >>
        a >> delim >> b >> delim >> c >> delim >> d >> delim) 
    {
        trim(data);

        if(data == "Data 1") {
            std::cout << a << ' ' << b << ' ' << c << ' ' << d << '\n';
        }
    }
}

Демо

1 голос
/ 22 февраля 2020

Да, легко извлечь вашу подстроку с помощью регулярного выражения. Нет необходимости использовать boost, вы также можете использовать существующую библиотеку регулярных выражений C ++.

Полученная программа очень проста.

Мы читаем все строки исходного файла в простой для l oop. Затем мы используем std::regex_match, чтобы сопоставить только что прочитанную строку с нашим регулярным выражением. Если мы нашли совпадение, то результат будет в std::smatch sm, группа 1.

И поскольку мы разработаем регулярное выражение для поиска двойных значений, мы получим именно то, что нам нужно, без каких-либо дополнительные пробелы.

Это мы можем преобразовать в двойные и показать результат на экране. И поскольку мы определили регулярное выражение, чтобы найти двойное число, мы можем быть уверены, что std::stod будет работать.

Полученная программа довольно проста и понятна:

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

// Please note. For std::getline, it does not matter, if we read from a
// std::istringstream or a std::ifstream. Both are std::istream's. And because
// we do not have files here on SO, we will use an istringstream as data source.
// If you want to read from a file later, simply create an std::ifstream inputFile1

// Source File with all data
std::istringstream inputFile1{ R"(
Random text
+-------------------+------+-------+-----------+-------+
|     Data          |   A  |   B   |     C     |   D   |
+-------------------+------+-------+-----------+-------+
|   Data 1          | 1403 |     0 |      2520 | 55.67 |
|   Data 2          | 1365 |     2 |      2520 | 54.17 |
|   Data 3          |    1 |     3 |      1234 | 43.12 |
Some more random text)" 
};

// Regex for finding the desired data
const std::regex re(R"(\|\s+Data 1\s+\|.*?\|.*?\|.*?\|\s*([-+]?[0-9]*\.?[0-9]+)\s*\|)");

int main() {

    // The result will be in here
    std::smatch sm;

    // Read all lines of the source file
    for (std::string line{}; std::getline(inputFile1, line);) {

        // If we found our matching string
        if (std::regex_match(line, sm, re)) {

            // Then extract the column D info
            double data1D = std::stod(sm[1]);

            // And show it to the user.
            std::cout << data1D << "\n";
        }
    }
}

Для большинства люди хитрая часть, как определить регулярное выражение. Есть такие страницы, как Онлайн тестер регулярных выражений и отладчик . Существует также разбивка для регулярного выражения и понятное объяснение.

Для нашего регулярного выражения

\|\s+Data 1\s+\|.*?\|.*?\|.*?\|\s*([-+]?[0-9]*\.?[0-9]+)\s*\|

мы получаем следующее объяснение:

\|  
    matches the character | literally (case sensitive)
\s+
    matches any whitespace character (equal to [\r\n\t\f\v ])
    + Quantifier — Matches between one and unlimited times, as many times as possible, giving back as needed (greedy)
    Data 1 matches the characters Data 1 literally (case sensitive)
\s+
    matches any whitespace character (equal to [\r\n\t\f\v ])
    + Quantifier — Matches between one and unlimited times, as many times as possible, giving back as needed (greedy)
\| 
    matches the character | literally (case sensitive)
.*?
    matches any character (except for line terminators)
    *? Quantifier — Matches between zero and unlimited times, as few times as possible, expanding as needed (lazy)
\| 
    matches the character | literally (case sensitive)
.*?
    matches any character (except for line terminators)
    *? Quantifier — Matches between zero and unlimited times, as few times as possible, expanding as needed (lazy)
\| 
    matches the character | literally (case sensitive)
.*?
    matches any character (except for line terminators)
\| 
    matches the character | literally (case sensitive)
\s*
    matches any whitespace character (equal to [\r\n\t\f\v ])

1st Capturing Group ([-+]?[0-9]*\.?[0-9]+)

\s*
    matches any whitespace character (equal to [\r\n\t\f\v ])
\| 
    matches the character | literally (case sensitive)

Кстати, более безопасное (более безопасное соответствие) регулярное выражение будет:

\|\s+Data 1\s+\|\s*?\d+\s*?\|\s*?\d+\s*?\|\s*?\d+\s*?\|\s*([-+]?[0-9]*\.?[0-9]+)\s*\|
...