在 istream 上使用 regex_iterator
Using a regex_iterator on an istream
我希望能够解决这样的问题:Getting std :: ifstream to handle LF, CR, and CRLF? 其中 istream
需要用复杂的定界符标记;这样,标记化 istream
的唯一方法是:
- 一次阅读
istream
一个字符
- 收集角色
- 当分隔符被击中时 return 集合作为标记
正则表达式非常擅长用复杂的分隔符标记字符串:
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
在上面,但吸食的步骤似乎是多余的。
是否存在 istream_iterator
和 regex_iterator
的邪恶组合,或者如果我想要它,我必须自己写吗?
我认为不是。 istream_iterator
具有 input_iterator_tag
标记,而 regex_iterator
期望使用双向迭代器 (bidirectional_iterator_tag
) 进行初始化。
如果您的定界符正则表达式足够复杂以致于避免自己读取流,那么最好的方法是确实吸食 istream
.
这个问题是关于代码外观的:
- 因为我们知道
regex
一次可以处理 1 个字符,所以这个问题要求使用库一次解析 istream
1 个字符,而不是在内部读取和解析istream
一次 1 个字符
- 由于一次解析
istream
1 个字符仍会将该字符复制到临时变量(缓冲区),此代码试图避免在内部缓冲所有代码,而是依赖于库来抽象它
C++11 的 regex
es 使用 ECMA-262,它不支持向前看或向后看: 这意味着 regex
可以仅使用 input_iterator_tag
,但显然在 C++11 中实现的那些没有。
另一方面,boost::regex_iterator
确实支持 boost::match_partial
标志(即 not available in C++11 regex
flags.) boost::match_partial
allows the user to slurp part of the file and run the regex
over that, on a mismatch due to end of input the regex
will "hold it's finger" at that position in the regex and await more being added to the buffer. You can see an example here: 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
是你最好的选择。
我希望能够解决这样的问题:Getting std :: ifstream to handle LF, CR, and CRLF? 其中 istream
需要用复杂的定界符标记;这样,标记化 istream
的唯一方法是:
- 一次阅读
istream
一个字符 - 收集角色
- 当分隔符被击中时 return 集合作为标记
正则表达式非常擅长用复杂的分隔符标记字符串:
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
在上面,但吸食的步骤似乎是多余的。
是否存在 istream_iterator
和 regex_iterator
的邪恶组合,或者如果我想要它,我必须自己写吗?
我认为不是。 istream_iterator
具有 input_iterator_tag
标记,而 regex_iterator
期望使用双向迭代器 (bidirectional_iterator_tag
) 进行初始化。
如果您的定界符正则表达式足够复杂以致于避免自己读取流,那么最好的方法是确实吸食 istream
.
这个问题是关于代码外观的:
- 因为我们知道
regex
一次可以处理 1 个字符,所以这个问题要求使用库一次解析istream
1 个字符,而不是在内部读取和解析istream
一次 1 个字符 - 由于一次解析
istream
1 个字符仍会将该字符复制到临时变量(缓冲区),此代码试图避免在内部缓冲所有代码,而是依赖于库来抽象它
C++11 的 regex
es 使用 ECMA-262,它不支持向前看或向后看: 这意味着 regex
可以仅使用 input_iterator_tag
,但显然在 C++11 中实现的那些没有。
boost::regex_iterator
确实支持 boost::match_partial
标志(即 not available in C++11 regex
flags.) boost::match_partial
allows the user to slurp part of the file and run the regex
over that, on a mismatch due to end of input the regex
will "hold it's finger" at that position in the regex and await more being added to the buffer. You can see an example here: 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
是你最好的选择。