8

编辑 3

当我被正则表达式卡住时,我采用了 good'ol 自定义解析方法。结果并没有那么糟糕,因为文件内容可以非常整齐地标记化,并且可以使用非常简单的状态机在循环中解析标记。那些想要检查的人,在 Stackoverflow here中的另一个问题中,有一段代码使用 range-for、ifstream 迭代器和自定义流标记器执行此操作。这些技术大大降低了执行自定义解析器的复杂性。

我想在第一部分中以两个为一组的捕获组对文件内容进行标记,然后逐行标记。我喜欢一个半功能性的解决方案,但我想学习如何让它变得更好。也就是说,没有“额外处理”来弥补我对捕获组的知识不足。接下来是一些初步的,最后是一个更准确的问题(行

const std::regex expression("([^:]+?)(^:|$)");

...是我想结合处理结果来询问的问题)。

基本上是这样定义的文件:

definition_literal : value_literal
definition_literal : value_literal
definition_literal : value_literal
definition_literal : value_literal
HOW TO INTERPRET THE FOLLOWING SECTION OF ROWS
[DATA ROW 1]
[DATA ROW 2]
...
[DATA ROW n]

其中每个数据行由一定数量的整数或浮点数组成,由空格分隔。每行具有与其他行一样多的数字(例如,每行可以有四个整数)。因此,“解释部分”基本上以纯文本形式在一行中讲述了这种格式。

我有一个几乎可以正常工作的解决方案,可以读取这样的文件:

int main() 
{
    std::ifstream file("xyz", std::ios_base::in);
    if(file.good())
    {
        std::stringstream file_memory_buffer;
        file_memory_buffer << file.rdbuf();
        std::string str = file_memory_buffer.str(); 
        file.close();

        const std::regex expression("([^:]+?)(^:|$)");
        std::smatch result;

        const std::sregex_token_iterator end;       
        for(std::sregex_token_iterator i(str.begin(), str.end(), expression); i != end; ++i)
        {
            std::cout << (*i) << std::endl;
        }
    }

    return EXIT_SUCCESS;
}

使用定义的正则表达式expression,它现在打印<value>定义文件的部分,然后是解释部分,然后是数据行。如果我将正则表达式更改为

"([^:]+?)(:|$)"

...它打印所有标记为一组的行,几乎就像我想要的那样,但是如何将第一部分标记为两组,其余部分逐行标记?

任何指针、代码、解释都非常受欢迎。谢谢。

编辑:

正如Tom Kerr已经指出的那样,但还有一些额外的点,这也是一次排练,或者如果你愿意,也可以编码 kata,不要编写自定义解析器,而是看看我是否可以——或者我们可以:-)——完成这与正则表达式。我知道正则表达式在这里不是最有效的事情,但这没关系。

我希望拥有的是类似于标题信息元组的列表(大小为 2 的元组),然后是 INTERPRET 行(大小为 1 的元组),我可以用它来选择一个函数来处理数据行(大小为 1 的元组)。

是的,“如何解释”行包含在一组定义明确的字符串中,我可以从头开始逐行读取,沿途拆分字符串,直到遇到其中一个解释行。我知道,这个正则表达式解决方案不是最有效的方法,但更像是编写 kata 代码让自己编写除客户解析器之外的其他东西(我上次用 C++ 编写已经有一段时间了,所以这也是在排练)。

编辑 2

我已经设法通过更改迭代器类型来访问元组(在这个问题的上下文中),就像这样

const std::sregex_iterator end;     
for(std::sregex_iterator i(str.begin(), str.end(), expression); i != end; ++i)
{
    std::cout << "0: " << (*i)[0] << std::endl;
    std::cout << "1: " << (*i)[1] << std::endl;
    std::cout << "2: " << (*i)[2] << std::endl;
    std::cout << "***" << std::endl;
}

尽管这与我想要的还有很长的路要走,但我尝试使用的正则表达式有问题。无论如何,这个新发现,另一种迭代器,也有帮助。

4

1 回答 1

1

我相信你正在尝试的是:

TEST(re) {
    static const boost::regex re("^([^:]+) : ([^:]+)$");

    std::string str = "a : b";
    CHECK(boost::regex_match(str, re));
    CHECK(!boost::regex_match("a:a : bbb", re));
    CHECK(!boost::regex_match("aaa : b:b", re));

    boost::smatch what;
    CHECK(boost::regex_match(str, what, re, boost::match_extra));
    CHECK_EQUAL(3, what.size());
    CHECK_EQUAL(str, what[0]);
    CHECK_EQUAL("a", what[1]);
    CHECK_EQUAL("b", what[2]);
}

我不确定我会在这种情况下推荐正则表达式。我认为您会发现一次读取一行,拆分:,然后修剪空间更易于管理。

我想如果您不能将下面的行作为哨兵,那将更加困难。通常我希望这样的格式在该行中是显而易见的,而不是标题每一行的格式。

HOW TO INTERPRET THE FOLLOWING SECTION OF ROWS
于 2012-06-29T22:44:06.067 回答