分析C++字符串
Parsing C++ strings
这里有很多关于发布字符串的帖子,但实际上似乎不符合我的目的。
我正在使用std::string
和所有标准库C++并且我有一个使用以下协议的文本文件:
TEXT1:TEXT2-TAB-TEXT3:TEXT4 TEXT5
当-TAB-
t
.
我想将所有文本放入字符串中(也可以是一个数组)。文件中的所有行都是这样写的,我尝试使用istringstream
但它没有功能,例如:iss >> text1 >> ":" >> text2 >> "t" >> text3 >> ":" >> text4 >> " " >> text5
.
我真的需要使用find
等的基本函数进行解析吗?那将是大量的工作(因为我有几个以不同格式编写的文件,我需要为所有这些文件创建一个通用函数),如果我别无选择,我会这样做。
那么......有没有办法通过以下方式解析字符串,在字符串之间使用已知字符?它不是一个特定的分隔符,因为每行都包含几个分隔符(一次是空格,然后是冒号等等)。我想使用C++标准库,而不是任何外部库,如 Boost。
编辑:C++11.
由于您使用的是 C++11 并且您的文本行遵守协议,因此用于模式匹配和信息提取的工具是正则表达式库中的功能。
匹配您的协议的模式可能如下所示...
\w+:\w+-\t-\w+:\w+\s\w+
。使用默认的 ECMAScript 语法。还有其他一些。
接下来,使用原始字符串文本初始化正则表达式对象...
regex pat{R("\
w+:\w+-\t-\w+:\w+\s\w+")};所以现在你的代码可以看起来像这样...
#include<regex>
...
regex pat{R("w+:w+-t-w+:w+sw+")};
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>()
};
您可能应该使用 std::getline 读取整行,然后解析该行,例如使用 find 或 find_first_of std::string 的方法查找't'
字符。
如果可能,请至少切换到 C++11,因为 C++11 的许多功能将使您能够编写更少的代码。特别是 std::find from <algorithm>
在与匿名 lambda 一起使用时很有帮助。
当然,您应该更正式地定义可接受的输入(也许使用一些 EBNF 符号,至少在注释中)。特别是,您的TEXT1
和TEXT2
中可以出现哪些确切的字符,TEXT3
和TEXT4
和TEXT5
。用什么编码?(UTF-8 具有多字节字符!
如果输入规范很复杂,您可以考虑使用一些解析器生成器,如 ANTLR 等。