正则匹配文本文件中的 3 种换行符 (行尾)
讨论
错误示范:
- 错误示范 1:
\n
—— 不匹配 Windows 行尾(CRLF); - 错误示范 2:
\r\n|\n
—— 不匹配旧式 mac 行尾(CR); - 错误示范 3:
[\r\n]{1,2}
—— 错误匹配“LFCR”; - 错误示范 4:
\r?\n
—— 不匹配旧式 mac 行尾(CR); - 错误示范 5:
\n|\r|\r\n
—— CR 和 LF 被拆开,如果存在 CRLF 将匹配出两个子串; - 错误示范 6:
\r\n?|\n
—— 这个的 bug 很难发现,问题在于:如果文件中存在 LFCRLF,则 LF 和 CRLF 都被匹配,但这种情况下应该只有 CRLF 才对; - 错误示范 7:
\r\n|\n|\r
—— 问题同上。
正确示范:\r?\n|(?<!\n)\r
—— 使用零宽断言。
这个正则 永远不会匹配到 LFCR;但也有弱点,即 LFCRLF 会匹配两个子串:LF 和 CRLF;但对于长度不大于 2 的纯 LF、CR 序列,都能够正确匹配。
所以就有了更正确一些的示范:\r\n|(?<!\r\n)\n(?!\r\n)|(?<!\r\n|\n)\r(?!\r\n|\n)
—— 看起来很长但思路很简单:
- 优先匹配 CRLF;
- 否则,匹配前后都没有 CRLF 的 LF;
- 否则,匹配前后都没有 CRLF 或 LF 的 CR。
- 否则,拒绝。
(你也可以调整单独 CR 和单独 LF 的优先级,但 CRLF 的优先级总是最高的)
当存在长度小于等于 3 的纯 LF、CR 构成的序列时,这个正则都能给出正确的匹配,但 LFCRCR 除外,它会匹配两个子串,即 LF 和末尾的 CR;为了解决这个问题就必须进一步增加规则。
我们发现,这样下去是没完没了的……正则表达式的长度取决于你要实现正确匹配的纯 LF、CR 序列的最大长度。
结论
对于不那么极端的情况,\r?\n|(?<!\n)\r
就可以正确匹配了。
抬杠
任何有限长的正则表达式 R R R 都无法正确匹配任意无限长的序列 S S S 中可接受的子串 σ R ( S ) \sigma_R(S) σR(S) ∈ Σ \Sigma Σ( Σ \Sigma Σ 是所有可接受的子串集合,且 c a r d ( Σ ) > 1 card(\Sigma) > 1 card(Σ)>1),使匹配到的子串集合 c a r d ( Σ ′ ) = 1 card(\Sigma ') = 1 card(Σ′)=1.
更多推荐
所有评论(0)