【问题标题】:How do I parse a line into pieces and ignore parts of it?如何将一行解析成几部分并忽略其中的一部分?
【发布时间】:2016-02-28 16:15:09
【问题描述】:

对不起。我以前不是克莱尔。我有一个包含以下格式数据的文件

A(3)

B(4),A

C(2),A

E(5),A

G(3),A

J(8),B,H

H(7),C,E,G

I(6),G

F(5),H

...

这些数据代表一个图表。

我将使用关键路径的方法来计算如何通过这个文本文件。

字符是步骤 int 是每个任务的长度 另一个字符是第一个字符之前的步骤

所以我创建了Task类来读取文件,它的构造函数有以下参数

    Tache::Tache(char step2, int duration, list<Task*> precedentTask)

    {

          this->step = step2;
          this -> duration = duration; 
          for(list<Task*>::iterator it = this-> precedentTask.begin(); it != this-> precedentTask.end(); it++)
         {
              this-> precedentTask.push_back(*it);
         }
   }

我主要添加了

string line;
list<Task> *allTaches = new list<Task>();

  while(getline(file, line, ','))
 {
       //I want to be able to receive the parse line from the file and add it like
     //allTaches.push_back(line)
     //But the format needs to look like (Char, duration, <a list of> PrecedentChar)           
     //when I do 
     cout<< line << Lendl;
    it prints 
    A(3)
    B(4)
    A
    C(2)
    A
    E(5)
    A 
 }

所以我不确定真正要做什么。

【问题讨论】:

  • 您解析显示Code here 的行。但说真的,您需要解释像这样调用Task 意味着什么——A 和B 是什么对象?字符串?宏定义?
  • @Leeor 问题似乎归结为:我已经在文件中格式化了文本,并且需要拆分每一行的部分,以便我可以在每一行上调用Task
  • @GlennTeitelbaum,可能,但在他改变问题之前,我认为情况会更糟,他希望按名称选择对象(否则正确的调用是例如 Task("B", 4, "A")
  • @Leeor 似乎第一个参数是单个字符,第三个参数是一些神秘的 task,所以是的,需要 OP 的一些帮助。那么这个问题有两个部分,解析和翻译,我可以帮助第一部分,巧妙地将第二部分留给读者练习
  • @GlennTeitelbaum,啊,错过了签名。

标签: c++ list file line push-back


【解决方案1】:

您可以使用正则表达式解析出您需要的部分,然后将它们传递给Task

在 c++ 中使用 std::regex 完成

下面的代码将帮助您了解如何解析这些部分,将它们应用到测试是一个简单的步骤,但最好由您完成以确保概念清晰。

首先我们需要一个正则表达式来抓取每个部分,这称为捕获组,所需的只是使用括号

如果我们分解你所拥有的 - 它是:

Something,我们不想要的开放括号,Something,我们不想要的闭合括号,我们不想要的逗号,以及Something

在简单的正则表达式中:

(.*)\((.*)\),(.*)

但事情从未如此简单

第一个 Something 以左括号结尾,所以我们想要除第一个左括号之外的所有内容:([^(]) ^ 表示不是,方括号 [] 表示每个字符

第二个Something以右括号结尾,所以我们有([^)])

第三个东西不包括可选的逗号,但我们可以使用(.*),然后将 , 分组为可选的* (可能有更好的方法来做到这一点)

我们还需要为编译器两次转义\,一次为正则表达式转义

我们还需要允许人们在其中输入随机空间,因此我们在所有休息时间添加*

这导致我们的正则表达式:

*([^(]*) *\\( *([^)]*) *\\) *(, *(.*))*

然后我们搜索,如果找到它将在结果中,我们可以迭代它以获取碎片。

#include <iostream>
#include <string>
#include <regex>

int main()
{
        // std::string seq = "A(4),B";
        std::string seq = "A(4)";

        try {
                std::regex rgx(" *([^(]*) *\\( *([^)]*) *\\) *(, *(.*))*");
                std::smatch result;
                if(std::regex_search(seq, result, rgx))
                {
                        std::cout << "Size=" << result.size() << std::endl;
                        for(size_t i=0; i<result.size(); ++i)
                        {
                                std::cout << result[i] << std::endl;
                        }
                }
                else
                {
                        std::cout << "NO MATCH" << std::endl;
                }
        } catch (std::regex_error& e) {

                std::cout << "BAD REGEX" << std::endl;
        }

}

【讨论】:

  • 这里有一个递归捕获。我不认为 C++ 支持那个?
【解决方案2】:

您实际上希望在这里为您的Tache 对象创建一个extraction operator。我将假设您的代码如下所示:

typedef char Task;

struct Tache {
    char step;
    int duration;
    list<Task> precedentTask;
};

您的提取运算符将是Tache 的方法。它的蛮力实现看起来像这样:

istream& operator>>(istream& lhs, Tache& rhs) {
    string line;

    getline(lhs, line, '\n');

    stringstream ss(line);

    ss >> rhs.step;
    ss.ignore(numeric_limits<streamsize>::max(), '(');
    ss >> rhs.duration;
    ss.ignore(numeric_limits<streamsize>::max(), ')');

    const regex re("\\s*,\\s*([a-zA-Z])");
    string precedentTasks;

    getline(ss, precedentTasks);

    rhs.precedentTask.clear();

    transform(sregex_token_iterator(cbegin(precedentTasks), cend(precedentTasks), re, 1), sregex_token_iterator(), back_insert_iterator<list<Task>>(rhs.precedentTask), [](const string& i) {
        return i.front();
    });

    return lhs;
}

Live Example

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-31
    • 1970-01-01
    • 2016-12-13
    相关资源
    最近更新 更多