问题描述
我的要求是匹配一个文本文件的每一行,包括每一行的行终止符,最多不包括最后一行的终止符,以考虑到Windows上生成的残缺,非POSIX兼容文件;每个行终止符可以是\n
或\r\n
。
我正在寻找性能最佳的正则表达式。
\n|\r\n|[^\r\n]++(\r\n|\n)?
一些评论:
- 由于三个备选方案无法在同一位置匹配,因此我认为这些备选方案的顺序无关紧要,而与引擎是DFA还是NFA无关;
-
++
而不是+
应该节省一些内存,但不会节省一些时间,因为不应该发生回溯。
在Code Review中,建议使用.*(\r?\n|$)
(如果[^\r\n]*(\r?\n|$)
也与.
或\n
相匹配,则使用\r
),但是这有一个缺陷:它也匹配文件末尾的空字符串。
建议的正则表达式可以像this一样进行改进:
(?=.).*(\r?\n)?
其中的前瞻性保证了.*
和(\r?\n)?
至少匹配一个字符,从而防止了文件末尾的空字符串匹配。
就性能而言,以上两个正则表达式中哪个应该更好?根据我的要求,还有其他更好的匹配方法吗?
请使用^
/ $
锚或类似的锚,请对此发表评论,因为它们的行为取决于引擎默认情况下是否将其视为多行。
解决方法
当每个后续模式在字符串中的相同位置均不匹配时,可以在regex中获得最佳性能。 .
和\R
是相反的模式,.
用于匹配除换行符以外的任何字符,\R
用于匹配任何换行符。
在C ++ Boost regex的上下文中,.
与任何字符匹配,包括换行符,而^
和$
的锚点是行(不是字符串)“终止符”,即您所使用的模式可以考虑使用is
(?-s)^(?!\z).*\R?
请参见regex demo。 详细信息:
-
(?-s)
-关闭单行模式,.
现在将无法匹配换行符 -
^
-行的开头(boost::regex
语法不需要(?m)
来使^
感知行,这是默认行为) -
(?!\z)
-如果当前位置位于字符串的最末端,则否定超前行为将使匹配失败 -
.*
-除换行符以外的任何零个或多个字符,并且尽可能多(此模式将regex索引移到行尾) -
\R?
-可选的换行符序列。
#include <boost/regex.hpp>
#include <iostream>
#include <string>
int main()
{
std::string text = "Line1\nLine2\r\nLine3\rLastLine\n";
boost::regex expression(R"((?-s)^(?!\z).*\R?)");
boost::smatch match;
boost::sregex_token_iterator iter(text.begin(),text.end(),expression,0);
boost::sregex_token_iterator end;
for( ; iter != end; ++iter ) {
std::cout << "'" << *iter << "'" << std::endl;
}
return 0;
}
输出:
'Line1
'
'Line2
'
'Line3
'
'LastLine
'