5

我希望能够解决这样的问题: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(); });

但是我不能在 aregex_iterator上使用 a istream:( 我的解决方案是先啜饮istream然后再将其regex_iterator碾过,但啜饮步骤似乎是多余的。

是否在某处有一个邪恶的组合istream_iteratorregex_iterator或者如果我想要它,我必须自己写吗?

4

2 回答 2

3

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

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

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

boost::regex_iterator另一方面,确实支持boost::match_partial标志(这在 C++11标志中不可用regex。)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. 包含boost总是会导致臃肿

回过头来回答这个问题:标准库regex_iterator不能对所需input_iterator_tag的全部内容进行操作istream。Aboost::regex_iterator允许用户啜饮少于整体istream。因为这是一个关于代码外观的问题,而且因为boost::regex_iterator最坏的情况需要对整个文件进行 slurping,所以这不是这个问题的好答案。

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

于 2015-04-28T12:07:17.380 回答
1

我想不是。istream_iteratorinput_iterator_tag标签,而regex_iterator期望使用双向迭代器 ( bidirectional_iterator_tag) 进行初始化。

如果您的定界符正则表达式足够复杂,可以避免自己读取流,那么最好的方法就是将istream.

于 2015-04-27T12:58:32.300 回答