讨论

错误示范:

  • 错误示范 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) —— 看起来很长但思路很简单:

  1. 优先匹配 CRLF;
  2. 否则,匹配前后都没有 CRLF 的 LF;
  3. 否则,匹配前后都没有 CRLF 或 LF 的 CR。
  4. 否则,拒绝。

(你也可以调整单独 CR 和单独 LF 的优先级,但 CRLF 的优先级总是最高的)

当存在长度小于等于 3 的纯 LF、CR 构成的序列时,这个正则都能给出正确的匹配,但 LFCRCR 除外,它会匹配两个子串,即 LF 和末尾的 CR;为了解决这个问题就必须进一步增加规则。

我们发现,这样下去是没完没了的……正则表达式的长度取决于你要实现正确匹配的纯 LF、CR 序列的最大长度。

结论

对于不那么极端的情况,\r?\n|(?<!\n)\r 就可以正确匹配了。

抬杠

任何有限长的正则表达式 RRR 都无法正确匹配任意无限长的序列 SSS 中可接受的子串 σR(S)\sigma_R(S)σR(S)Σ\SigmaΣΣ\SigmaΣ 是所有可接受的子串集合,且 card(Σ)>1card(\Sigma) > 1card(Σ)>1),使匹配到的子串集合 card(Σ′)=1card(\Sigma ') = 1card(Σ)=1.

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐