【问题标题】:Matching at line endings在行尾匹配
【发布时间】:2013-10-01 23:54:51
【问题描述】:

这是一件非常琐碎的事情:替换一行

  • 可能包含尾随空格
  • 以 '\n'、'\r'、'\r\n' 或无结尾

由不包含尾随空格并以 '\n' 结尾的行。

我想我可以通过一个简单的正则表达式来做到这一点。在这里,"\\s+$" 不起作用,因为 $ 在最终的 \n 之前匹配。这就是为什么有\\z。至少我是这么认为的。但是

"\n".replaceAll("\\s*\\z", "\n").length()

返回 2。实际上,$\\z\\Z 在这里执行完全相同的操作。我很困惑...


Alan Moore 的解释很有帮助,但我才刚刚想到,在 EOF 替换任意最终空白垃圾我可以做到

replaceFirst("\\s*\\z"", "\n");

而不是replaceAll。完成上述所有操作的简单解决方案是

replaceAll("(?<!\\s)\\s*\\z|[ \t]*(\r?\n|\r)", "\n");

恐怕,不是很快,但可以接受。

【问题讨论】:

    标签: java regex eol


    【解决方案1】:

    实际上,\z 是无关紧要的。在第一次匹配尝试时,\s* 使用换行符 (\n) 并且 \z 成功,因为它现在位于字符串的末尾。因此它用换行符替换换行符,然后尝试匹配换行符 after 的位置,即字符串的结尾。它再次匹配,因为\s* 被允许匹配空字符串,所以它用另一个换行符替换空字符串。

    您可能希望它继续不匹配任何内容并用无限换行符替换它,但这是不可能的。除非您重置它,否则正则表达式不能在同一位置匹配两次。或者更准确地说,开始在同一个位置。在这种情况下,第一场比赛从位置 #0 开始,第二场比赛从位置 #1 开始。

    顺便说一下,\s+$ 应该匹配字符串"\n"$ 可以匹配字符串的最末尾以及字符串末尾的行分隔符之前。

    更新:为了处理这两种情况:(1) 在行尾删除不需要的空格,以及 (2) 在没有不需要的空格的情况下添加换行符,我最好的选择是使用lookbehind:

    line = line.replaceAll("(?<!\\s)\\s*\\z", "\n");
    

    这仍然会匹配每一行,但每行只会匹配一次。

    【讨论】:

    • 实际上,\z 无关紧要。 - 不可能,因为我真的不想替换中间的空格。 $ 可以匹配字符串的最末尾以及字符串末尾的行分隔符之前。 - 我知道,这就是我使用\z 的原因,因为我只想匹配到最后。
    • 关于*... 最初我使用的是+,但后来我也想了解缺少行尾的情况。我的错。所以现在(s + '\n').replaceFirst("\\s+\\z", "\n") 似乎可以工作,但对于这样一个微不足道的任务来说,它太复杂了。
    • 不,我的意思是它没有效果在你的例子中。正则表达式只有两个位置可以开始匹配:换行之前和之后。但我想我现在明白了;我会更新我的答案。
    • 与此同时,我发现一个正则表达式仅匹配“错误”行:"\\s+\n|\\s*[\\s&amp;&amp;[^\n]]\\z|(?&lt;=\\S)\\z"。它又可怕又慢,所以我试试你的。
    【解决方案2】:

    你能做如下的事情吗?

     String result = myString.trim() + '\n';
    

    【讨论】:

    • 不完全是……我只能向右修剪,必须保留缩进。我找到了一个(相当丑陋的)解决方案,但我真正的问题是正则表达式并没有像我一直认为的那样工作(我经常使用正则表达式)。
    猜你喜欢
    • 1970-01-01
    • 2019-02-21
    • 2011-06-30
    • 2013-06-22
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多