解析复杂的字符串

时间:2011-11-30 07:03:21

标签: c++ string parsing

我需要按以下顺序读取字符串:

  1. 读取以空格分隔的任意数量的数字,丢弃除最后一个之外的所有数字,将其保存到n
  2. 读取一个空格,后跟n个字符,后跟空格,只保存字符
  3. 再读两个用空格分隔的数字并保存它们
  4. 我想过使用字符串流来读取数字并停在字符串上,但我不知道如何预测字符串流中的字符串并停止读取数字而不将字符串“读取”为数字并终止字符串流。
    如何预测字符串并停止读取数字呢? 有没有更好的方式来阅读这整个模式?
    我使用C ++ 11。

    编辑:
    示例输入:

    1 2 3 4 6 abc de 7 8
    

    例外输出:

    The string: 'abc de'
    Number 1: 7
    Number 2: 8
    

4 个答案:

答案 0 :(得分:3)

我认为有两个选项:使用regular expression,或使用某种状态机逐字逐句输入。

修改

关于那个状态机......可能是这样的:

// Pre-conditions: "str" is a std::string containing the whole string to be parsed

enum class states
{
    GET_LENGTH,           // Looking for the embedded string length
    GET_LENGTH_OR_STRING, // Get the embedded string, or the length
    GET_STRING,           // Getting the embedded string
    GET_NUMBER_1,         // Look for the first number after the string
    GET_NUMBER_2,         // Look for the second number after the string
};

int         len = 0; // Length of the embedded string
std::string tmp;     // Temporary string
int         n1, n2;  // The numbers after the string
states      state = GET_LENGTH;

for (auto ci = str.begin(); ci != str.end(); )
{
    // Skip whitespace
    while (isspace(*ci))
        ci++;

    switch (state)
    {
    case GET_LENGTH:
        while (isdigit(*ci))
            tmp += *ci++;
        len = strtol(tmp.c_str(), nullptr, 10);

        state = GET_LENGTH_OR_STRING;
        break;

    case GET_LENGTH_OR_STRING:
        if (isdigit(*ci))
            state = GET_LENGTH;
        else
            state = GET_STRING;
        break;

    case GET_STRING:
        tmp = std::string(ci, ci + len);
        ci += len;
        tmp = "";
        state = GET_NUMBER_1;
        break;

    case GET_NUMBER_1:
        while (isdigit(*ci))
            tmp += *ci++;
        n1 = strtol(tmp.c_str(), nullptr, 10);
        break;

    case GET_NUMBER_2:
        while (isdigit(*ci))
            tmp += *ci++;
        n2 = strtol(tmp.c_str(), nullptr, 10);
        break;
    }
}

免责声明:未经测试,只是直接在浏览器中“按原样”编写。

代码可能会更好,就像获取长度和尾随数字的状态基本相同,可以放在单独的函数中共享它。

答案 1 :(得分:1)

我不太了解C ++,但你不能:

  • 解析空间分隔符上的整个输入

  • 查看该列表:

    • 数字时,将数字存储在同一个var

    • 存储n个字符(我假设你的意思是那里有一个字符串)

    • 存储最后两个数字

答案 2 :(得分:1)

由于您使用的是C ++ 11编译器,您可以在AX中编写语法:

// input text
std::string txt("1 2 3 4 6 abc de 7 8");

// assume spaces are ' ' and tabs
auto space = axe::r_any(" \t");

// create a number rule that stores matched decimal numbers in 'n'
int n = 0;
auto number_rule = axe::r_decimal(n) % +space;

// create a string rule, which stops when reaching 'n' characters
std::string s;
int count = 0;
auto string_rule = space & 
    *(axe::r_any() & axe::r_bool([&](...){ return n > count++; })) >> s;

// tail rule for two decimal values
int n1 = 0, n2 = 0;
auto tail_rule = +space & axe::r_decimal(n1) & +space & axe::r_decimal(n2);

// a rule for entire input text
auto rule = number_rule & string_rule & tail_rule;
// run parser
rule(txt.begin(), txt.end());
// dump results, you should see: n=6, s=abc de, n1=7, n28
std::cout << "\nn=" << n << ", s=" << s << ", n1=" << n1 << ", n2" << n2;

答案 3 :(得分:1)

只需使用标准C ++流功能,即可在不使用任何正则表达式的情况下执行此操作。下面是使用std :: cin作为输入流的示例,但如果要从字符串中读取,则可以使用字符串流。

#include <iostream>
#include <iomanip>
#include <vector>

int main(int argc, char* const argv[]) {

        int n,tmp;

        /// read integers, discarding all but the last
        while(std::cin >> tmp)
                n = tmp;
        if(std::cin.bad()) {
                std::cout << "bad format 1" << std::endl;
                return -1;
        }

        /// skip whitespaces
        std::cin >> std::ws;
        std::cin.clear();

        /// read a string of 'n' characters
        std::vector<char> buffer(n+1, '\0');
        if(! std::cin.read(buffer.data(), n) ) {
                std::cout << "bad format 2" << std::endl;
                return -1;
        }
        std::string s(buffer.data());

        /// Read 2 numbers
        int nb1, nb2;
        if(! (std::cin >> nb1 >> nb2)) {
                std::cout << "bad format 3" << std::endl;
                return -1;
        }

        std::cout << "The string: " << s << std::endl;
        std::cout << "Number 1: " << nb1 << std::endl;
        std::cout << "Number 2: " << nb2 << std::endl;
        return 0;
}