当我遇到正则表达式时,我使用了good'ol自定义解析方法。它并没有那么糟糕,因为文件内容可以非常巧妙地进行标记,并且可以使用 very 简单状态机在循环中解析标记。那些想要检查的人,在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>
部分,然后打印解释部分,然后逐个打印数据行。如果我将正则表达式更改为
"([^:]+?)(:|$)"
...它打印出所有标记为一组的行,几乎就像我想的那样,但是如何将第一部分分为2组,其余部分逐行标记?
真正欢迎任何指针,代码和解释。感谢。
正如 Tom Kerr 已经提到的那样,但是还有一些额外的要点,这也是排练,或编码kata(如果你愿意的话),不是为了编写自定义解析器,而是为了看看我是否可以 - - 或者我们可以:-) - 用正则表达式完成这个。我知道正则表达式不是最有效的方法,但这并不重要。
我希望拥有的是一个标题信息元组列表(大小为2的元组),然后是INTERPRET行(大小为1的元组),我可以用它来选择一个函数来做什么使用数据行(大小为1的元组)。
是的,“HOW TO INTERPRET”行包含在一组明确定义的字符串中,我可以从头开始逐行读取,沿途分割字符串,直到满足其中一条INTERPRET行。我知道,这个正则表达式解决方案不是最有效的方法,但更像编码kata让自己编写除客户解析器以外的其他内容(而且我最近一次用C ++编写,所以这也是排练)。
我已经设法通过更改迭代器类型来访问元组(在这个问题的上下文中),就像这样
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;
}
虽然这仍然不像我想要的那样,但我正在尝试使用的正则表达式出现了问题。无论如何,这种新的发现,另一种迭代器,也有帮助。
答案 0 :(得分: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