Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从输入流中读取行,能够跳过块_C++_Stream - Fatal编程技术网

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
    }
}