解析 C++ 字符串

Parsing C++ strings

这里有很多关于发布字符串的帖子,但似乎不符合我的目的。

我正在使用 std::string 和所有 C++ 标准库,并且我有一个使用以下协议的文本文件:

TEXT1:TEXT2-TAB-TEXT3:TEXT4 TEXT5

-TAB-\t时。

我想把所有的文本都变成字符串(也可以是数组)。文件中的所有行都是这样写的,我尝试使用 istringstream 但它没有功能,例如:iss >> text1 >> ":" >> text2 >> "\t" >> text3 >> ":" >> text4 >> " " >> text5.

我真的需要使用 find 等的基本功能进行解析吗?那只是大量的工作(因为我有几个以不同格式编写的文件,我需要为所有这些文件制作一个通用函数),如果我别无选择,我会这样做。

所以...有什么方法可以通过以下方式在字符串之间使用已知字符来解析字符串?它不是一个特定的分隔符,因为每一行都包含几个分隔符(一次是 space,然后是一个冒号等等)。我想使用 C++ 标准库而不是任何外部库,例如 Boost。

编辑: C++11.

您可能应该使用 std::getline then parse that line, e.g. finding the '\t' character using find or find_first_of method of std::string 阅读整行。

如果可能,切换到C++11 at least, since many features of C++11 would enable you to write less code. In particular std::find from <algorithm> is helpful when used with an anonymous lambda

当然,您应该更正式地定义可接受的输入(也许 EBNF notations, at least in comments). In particular, what exact characters can appear in your TEXT1 and TEXT2 and TEXT3 and TEXT4 and TEXT5. In what encoding? (UTF-8 有一些多字节字符!)。

如果输入规格比较复杂,可以考虑使用一些parser generator like ANTLR等。

由于您使用的是 C++11 并且您的文本行遵守协议,因此用于模式匹配和信息提取的工具是在正则表达式库中找到的功能。

与您的协议相匹配的模式可能如下所示...

\w+:\w+-\t-\w+:\w+\s\w+

... 使用默认的 ECMAScript 语法。还有几个。

接下来,使用原始字符串文字来初始化正则表达式对象...

正则表达式 pat{R("\w+:\w+-\t-\w+:\w+\s\w+")};

所以现在您的代码可以如下所示...

#include<regex>
...

regex pat{R("\w+:\w+-\t-\w+:\w+\s\w+")};
smatch m;

while (cin >> str) {  // where str is your line of formatted text
    bool match = regex_search(str, m, pat);
    for (int i = 0; i < m.size(); i++) {
        cout << m[i].str() << " "; // to make sure each component was matched
    }   
}

顺便说一句,smatch就像一个容器,可以迭代,所以非常方便。

注意:以上代码不能保证有效,仅供参考。

因为你有一个固定的字符来标记每个字段的结尾,所以像正则表达式这样的东西有点过分了。我只是使用 std::getline 来阅读每个字段。

我首先在一行中为字段定义一个结构,然后重载 operator>> 以读取其中一个结构:

struct line { 
    std::string text1, text2, text3, text4, text5;

    friend std::istream &operator>>(std::istream &is, line &l) {
        std::getline(is, l.text1, ':');
        std::getline(is, l.text2, '\t');
        std::getline(is, l.text3, ':');
        std::getline(is, l.text4, ' ');
        std::getline(is, l.text5);
        return is;
    }
};

这样,您可以阅读如下一行:

line x;

std::cin >> x;

...或者,如果您有一个充满这样行的整个文件,您可以将它们全部读入一个向量中,例如:

std::ifstream infile("whatever.dat");

std::vector<line> lines {
    std::istream_iterator<line>(lines),
    std::istream_iterator<line>()
};