我有一个带有一系列类似字节码指令的输入流
function foo
push x
pop y
...
return
function bar
...
return
function other
...
即一系列背靠背的函数声明。每个功能都是从一个“功能”到下一个“功能”定义的。函数中可能有多个“返回”,因此我不能将其用作分隔符。所有指令都必须在函数内(即流的第一行始终是“函数”,最后一行始终是“返回”)。
我想基本上从列表中删除某些功能。我有一个我想保留的函数列表,我考虑过复制到输出流,跳过任何不在列表中的函数,比如
vector<string> wanted_functions = { "foo", "other" }
ostringstream oss;
bool skip = false;
for (string line; getline(input_stream, line);) {
istringstream iss(line);
string command;
iss >> command;
if (command == "function") {
skip = false;
string function_name;
iss >> function_name;
if (std::find(wanted_function.begin(), wanted_functions.end(), function_name)
== wanted_functions.end()) {
skip = true;
}
if (!skip) oss << line;
}
我没有测试过上面的解决方案;看起来它可能有用,但我认为它不是很优雅。 我觉得流迭代器在这里会很好,但我不知道如何使用它们。我如何使用迭代器或原生流方法(如 ignore() 或 seekg())实现跳过行为?
奖励:如果有更好的方法来阅读为他们创建新流的行中的前两个词,我也很想知道。
编辑:函数总是顺序的。没有嵌套函数。 IE。 “function”总是紧跟在“return”之前。
最佳答案
如果它是文本,你不能轻易地跳转/跳过(seekg
)而不实际阅读它,因为你没有已知的偏移量(许多二进制文件格式将包含此类信息),但你可以只过滤您阅读的内容,您问题中的代码几乎可以做到这一点。
istream_iterator<std:string>
会给你每个单词/空格分隔,但你不能告诉新行在哪里。你可以做一个istream_iterator
这将改为读取行,但最简单的方法涉及子类化 std::string
重新定义 operator >>
,但这基本上就是getline
无论如何都会得到你,或者你可以制作包含更多有用信息的自己的类型(如下)。
您可能会使用 std::unordered_set<std::string> wanted_functions
因为这比搜索 std::vector
更容易检查项目是否存在(与 std::find
或类似)。 skip
当您将其设置为“不需要的”功能时,最终也会有点奇怪地工作,然后像if (!unwanted)
那样做.
unordered_set<string> wanted_functions = { "foo", "other" };
bool is_wanted_function = false;
for (string line; getline(input_stream, line);) {
istringstream iss(line);
string command;
iss >> command;
if (command == "function") {
string function_name;
iss >> function_name;
is_wanted_function = wanted_functions.count(function_name) != 0;
}
if (is_wanted_function) {
oss << line << std::endl;
}
}
is_wanted_function
的替代品标志将是使用 if (command == "function") {
中的函数,这需要更仔细地管理读取下一行,以免不小心跳过内循环之后的那一行
unordered_set<string> wanted_functions = { "foo", "other" };
string line;
getline(input_stream, line);
while (input_stream) {
istringstream iss(line);
string command;
iss >> command;
if (command == "function") {
string function_name;
iss >> function_name;
if (wanted_functions.count(function_name)) {
oss << line << std::endl;
while (getline(input_stream, line) && line.rfind("function", 0) != 0) {
oss << line << std::endl;
}
continue; // already have a line
}
}
getline(input_stream, line); // next line
}
我不认为这是很大的改进,但如果实际解析( iss >> command;
、 iss >> function_name
等)在别处重构,那么它会更简单一些。
您可能会进行实际的解析(获取像“function”这样的命令名称,以及像“foo”这样的参数)它自己的类可以整理istringstream iss(line); iss >> command;
等直接在此代码中。
istream_iterator
基本上只使用 operator >>
在流处于失败状态之前获取下一个项目,因此可以与您自己的类型一起使用,尽管您可以在没有 istream_iterator
的情况下自己做一些非常相似的事情。 .
class command
{
public:
const std::string &cmd()const { return _cmd; }
const std::string &source_line()const { return _source_line; }
const std::string &arg(size_t i)const
{
if (i < _args.size()) return _args[i];
else throw std::out_of_range("Command does not have this many arguments.");
}
friend std::istream &operator >> (std::istream &is, command &cmd)
{
if (std::getline(is, cmd._source_line))
{
std::stringstream ss(cmd._source_line);
ss >> cmd._cmd;
cmd._args.clear(); // istream_iterator uses the same command object every time
while (true)
{
std::string val;
ss >> val;
if (!ss) break;
cmd._args.push_back(std::move(val));
}
}
return is;
}
private:
std::string _source_line;
std::string _cmd;
std::vector<std::string> _args;
};
int main()
{
using namespace std;
std::stringstream input_stream(
"function foo\n"
"push x\n"
"pop y\n"
"...\n"
"return\n"
"function bar\n"
"...\n"
"return\n"
"function other\n"
"...\n"
"return\n");
std::ostream &oss = std::cout;
std::unordered_set<string> wanted_functions = { "foo", "other" };
std::istream_iterator<command> eos; // end of stream
std::istream_iterator<command> it(input_stream); // iterator
while (it != eos)
{
if (it->cmd() == "function" && wanted_functions.count(it->arg(0)))
{
do
{
oss << it->source_line() << std::endl;
} while (++it != eos && it->cmd() != "function");
}
else ++it; // on true the while loop already advanced
}
}
istream_iterator
当然也带来了与其他基于迭代器的算法和构造函数( std::find
等)的兼容性,您可以从中构建一些更复杂的东西。例如,如果您在此之上添加另一层以创建一个 istream_iterator<function>
, 那么也许你可以使用 Boost C++ filter_iterator
,然后您将拥有一个仅包含所需函数的迭代器。
请注意,如果您需要开始处理任何嵌套结构(如 if (...) { ... } else if (...) { ... }
),您可能会发现解析为树结构比对平面序列进行操作更方便。请参见抽象语法树。这在某种程度上取决于您的语法,例如如果你只使用 goto if
偏移量/标签而不是 while(expr)
, if(expr)
, else if
, else
等类型结构。
关于c++ - 从输入流中读取具有跳过 block 能力的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59269869/