c++ - 在 istream 上使用 regex_iterator

标签 c++ regex iterator istream istream-iterator

我希望能够解决这样的问题:Getting std :: ifstream to handle LF, CR, and CRLF? istream 需要用复杂的定界符标记;这样,标记化 istream 的唯一方法是:

  1. istream 中一次读取一个字符
  2. 收集角色
  3. 当命中分隔符时,将集合作为标记返回

正则表达式非常擅长用复杂的分隔符标记字符串:

string foo{ "A\nB\rC\n\r" };
vector<string> bar;

// This puts {"A", "B", "C"} into bar
transform(sregex_iterator(foo.cbegin(), foo.cend(), regex("(.*)(?:\n\r?|\r)")), sregex_iterator(), back_inserter(bar), [](const smatch& i){ return i[1].str(); });

但我不能在 istream 上使用 regex_iterator :( 我的解决方案是吞噬 istream 然后运行 ​​regex_iterator 覆盖它,但 slurping 这一步似乎是多余的。

是否存在 istream_iteratorregex_iterator 的邪恶组合,或者如果我想要它,我必须自己编写吗?

最佳答案

这个问题是关于代码外观的:

  1. 因为我们知道 regex 一次只能处理 1 个字符,所以这个问题要求使用库一次解析 istream 1 个字符,而不是一次在内部读取和解析 istream 1 个字符
  2. 由于一次解析 istream 1 个字符仍会将该字符复制到临时变量(缓冲区),因此此代码试图避免在内部缓冲所有代码,这取决于库而不是抽象那个

C++11 的 regexes 使用不支持向前看或向后看的 ECMA-262:https://stackoverflow.com/a/14539500/2642059这意味着 regex 可以仅使用 input_iterator_tag 进行匹配,但显然在 C++11 中实现的那些不能。

boost::regex_iterator 另一方面支持 boost::match_partial 标志(即 not available in C++11 regex flags 。)boost::match_partial 允许用户吞咽文件的 part 并在其上运行 regex,如果由于输入结束而导致不匹配,regex 将在正则表达式中的那个位置“按住它的手指”并等待更多被添加到缓冲区。您可以在此处查看示例:http://www.boost.org/doc/libs/1_55_0/libs/regex/doc/html/boost_regex/partial_matches.html在一般情况下,如 "A\nB\rC\n\r",这可以节省缓冲区大小。

boost::match_partial 有 4 个缺点:

  1. 在最坏的情况下,像 "ABC\n" 这样可以节省用户 no 大小,他必须吞噬整个 istream<
  2. 如果程序员可以猜到缓冲区大小太大,即它包含分隔符和更多的数量,那么减少缓冲区大小的好处就会被浪费掉
  3. 任何时候选择的缓冲区大小太小,与整个文件的 slurping 相比都需要额外的计算,因此这种方法在定界符密集的字符串中表现出色
  4. 包含boost总是会导致膨胀

回过头来回答这个问题:标准库 regex_iterator 不能对 input_iterator_tag 进行操作,需要整个 istreamboost::regex_iterator 允许用户可能 比整个 istream 吃得更少。因为这是一个关于代码外观的问题,而且因为 boost::regex_iterator 的最坏情况无论如何都需要对整个文件进行 slurping,所以这不是这个问题的好答案。

为了最好的代码外观,吞噬整个文件并在其上运行标准的 regex_iterator 是最好的选择。

关于c++ - 在 istream 上使用 regex_iterator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29895519/

相关文章:

c++ - 使用给定的第一个和最后一个迭代器迭代范围

c++ - 为什么它打印循环链表中的最后一个元素?

c++ - 不同字符编码之间的故障安全转换

regex - 在 OSX 上使用 sed 设置 PermitRootLogin

c# - 用于拆分 Amazon S3 存储桶日志列的正则表达式?

c++ - 将行添加到 GTKTreeView 时出现段错误

c# - 通过 tcp 拆分消息

c++ - 如何使用 C++ 从字符串中删除前导零?

regex - 用注释替换字符串的特定出现

c++ - 带有 LinkedList 的迭代器类?