C++ 从输入流中读取行,能够跳过块
我有一个带有一系列字节码指令的输入流C++ 从输入流中读取行,能够跳过块,c++,stream,C++,Stream,我有一个带有一系列字节码指令的输入流 function foo push x pop y ... return function bar ... return function other ... 即一系列背靠背的函数声明。每个函数从一个函数定义到下一个函数。一个函数中可能有多个返回,因此我不能将其用作分隔符。所有指令必须位于函数内部,即流的第一行始终是函数,最后一行始终是返回 我想基本上从列表中删除某些函数。我有一个我想要保留的函数列表,我考虑复制到输出流,跳过列表中没有的函数,比如 vec
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这样的原生流方法来实现跳过行为
奖励:如果有更好的方法来阅读这行的前两个单词,那就是为他们创建一个新的流,我也想知道
编辑:函数始终是连续的。没有嵌套函数。也就是说,函数的前面总是紧接着返回。如果它是文本,你不能简单地跳转/跳过seekg而不实际读取它,因为你没有已知的偏移量,很多二进制文件格式都会包含这样的信息,但你可以只过滤你读的内容,你问题中的代码几乎就是这样做的 istream_迭代器将为您提供每个单词/空格分隔符,但您无法知道新行在哪里。您可以创建一个istream_迭代器来读取行,但最简单的方法是对std::string进行子分类,以重新定义运算符>>,但这基本上就是getline让您得到的,或者您也可以创建自己的类型,其中包含以下更有用的信息 您可以使用std::unordered_set wanted_函数,因为这比使用std::find或类似工具搜索std::vector更容易检查项目是否存在。skip的工作也有点奇怪,因为您正在将其设置为不需要的函数,然后像if!不需要的 我不认为这是一个很大的改进,但是如果实际解析iss>>命令;,iss>>函数名等在其他地方进行了重构,这样会更简单一些 您可能会使实际的解析得到类似于函数的命令名,以及类似于foo的参数,这是它自己的类,它可以整理istringstream issline;iss>>命令;等直接在本代码中 istream_迭代器基本上只使用操作符>>来获取下一个项,直到流处于失败状态,因此可以用于您自己的类型,尽管您可以在没有istream_迭代器的情况下获得类似的结果 当然,istream_迭代器也带来了与其他基于迭代器的算法和构造函数std::find等的兼容性,您可以从中构建一些更复杂的东西。例如,如果在这个上面添加另一个层来创建一个istRAMMyIdter,那么也许你可以使用Boost C++ + FieldIt迭代器,然后你就可以得到一个只需要你所需函数的迭代器。
请注意,如果您需要开始处理任何嵌套结构,如if。。。{…}如果。。。{…},您可能会发现解析到树结构中比在平面序列上执行操作更方便。请参阅抽象语法树。这在某种程度上取决于您的语法,例如,如果您使用just goto if offset/label而不是whileexpr、ifexpr、else if、else等类型构造。您可以将其重构为多个函数或一个类,使其更易于阅读,但逻辑必须与嵌套函数基本相同,还是它总是起作用。。。东西返回函数。。。东西返回?@FireLancer他们总是按顺序进行;没有嵌套函数。条件/多次返回如何?作用如果返回其他。。。返回函数…下一个…@FireLancer正如我提到的,在一个函数中可能有多个条件返回,这就是为什么它不能用作分隔符的原因。这是低级字节码,因此if-else语句实际上实现为不同类型的跳转。不过,跳跃本身并不重要。解决方案应该复制或排除当前函数中的所有内容,直到并排除下一个函数。有很多很好的建议。后来我意识到我已经在程序中解析到一个结构中了,所以我将其向上移动并使用了第三种解决方案。
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;
}
}
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
}
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
}
}