我希望能够解决这样的问题:Getting std :: ifstream to handle LF, CR, and CRLF? istream
需要用复杂的定界符标记;这样,标记化 istream
的唯一方法是:
- 在
istream
中一次读取一个字符 - 收集角色
- 当命中分隔符时,将集合作为标记返回
正则表达式非常擅长用复杂的分隔符标记字符串:
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_iterator
和 regex_iterator
的邪恶组合,或者如果我想要它,我必须自己编写吗?
最佳答案
这个问题是关于代码外观的:
- 因为我们知道
regex
一次只能处理 1 个字符,所以这个问题要求使用库一次解析istream
1 个字符,而不是一次在内部读取和解析istream
1 个字符 - 由于一次解析
istream
1 个字符仍会将该字符复制到临时变量(缓冲区),因此此代码试图避免在内部缓冲所有代码,这取决于库而不是抽象那个
C++11 的 regex
es 使用不支持向前看或向后看的 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 个缺点:
- 在最坏的情况下,像
"ABC\n"
这样可以节省用户 no 大小,他必须吞噬整个istream
< - 如果程序员可以猜到缓冲区大小太大,即它包含分隔符和更多的数量,那么减少缓冲区大小的好处就会被浪费掉
- 任何时候选择的缓冲区大小太小,与整个文件的 slurping 相比都需要额外的计算,因此这种方法在定界符密集的字符串中表现出色
- 包含
boost
总是会导致膨胀
回过头来回答这个问题:标准库 regex_iterator
不能对 input_iterator_tag
进行操作,需要整个 istream
。 boost::regex_iterator
允许用户可能 比整个 istream
吃得更少。因为这是一个关于代码外观的问题,而且因为 boost::regex_iterator
的最坏情况无论如何都需要对整个文件进行 slurping,所以这不是这个问题的好答案。
为了最好的代码外观,吞噬整个文件并在其上运行标准的 regex_iterator
是最好的选择。
关于c++ - 在 istream 上使用 regex_iterator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29895519/