在 istream 上使用 regex_iterator

Jon*_*Mee 5 c++ regex iterator istream-iterator istream

我希望能够解决这样的问题:Getting std::ifstream to handle LF, CR, and CRLF? 其中 anistream需要通过复杂的分隔符进行标记;这样标记化的唯一方法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(); });
Run Code Online (Sandbox Code Playgroud)

但我不能regex_iterator在 a 上使用 a istream:( 我的解决方案是吸食istream然后运行regex_iterator它,但吸食步骤似乎是多余的。

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

Jon*_*Mee 3

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

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

C++11 的regexes 使用 ECMA-262,不支持向前看或向后看:/sf/answers/1017765031/这意味着 aregex可以仅使用 an 进行匹配input_iterator_tag,但显然是在 C++ 中实现的11 不。

boost::regex_iterator另一方面,确实支持该boost::match_partial标志(在 C++11regex标志中不可用。)boost::match_partial允许用户读取文件的一部分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"用户就无法节省任何大小,他必须吞掉整个istream
  2. 如果程序员可以猜测缓冲区大小太大,即它包含分隔符和更多的数量,那么减小缓冲区大小的好处就被浪费了
  3. 任何时候选择的缓冲区大小太小,与整个文件的slurping相比,都需要额外的计算,因此该方法在分隔符密集的字符串中表现出色
  4. 包含boostalways会导致膨胀

回过头来回答这个问题:标准库regex_iterator无法对所需input_iterator_tag的全部内容进行操作istream。Aboost::regex_iterator允许用户吸食少于全部istream。因为这是一个关于代码外观的问题,而且因为boost::regex_iterator最坏的情况无论如何都需要读取整个文件,所以这不是这个问题的一个很好的答案。

regex_iterator为了获得最佳的代码外观,最好的选择是吸收整个文件并在其上运行标准。