【问题标题】:How can I write a regex in Java that will perform a .replaceFirst on a group that is not in a comment?如何在 Java 中编写一个 .replaceFirst 对不在评论中的组执行 .replaceFirst 的正则表达式?
【发布时间】:2013-02-14 19:44:59
【问题描述】:

所以我需要返回修改后的字符串,它在跳过 cmets 时用另一个令牌替换令牌的第一个实例。这是我所说的一个例子:

This whole quote is one big String
-- I don't want to replace this @@
But I want to replace this @@!

作为一名前 .NET 开发人员,我认为这很容易。我只会像这样消极地回顾一下:

(?<!--.*)@@

但后来我了解到 Java 无法做到这一点。所以在得知花括号没问题后,我尝试了这个:

(?<!--.{0,9001})@@

这并没有引发异常,但它确实与评论中的 @@ 匹配。

当我使用 Java 正则表达式测试器测试此正则表达式时,它按预期工作。我能想到的唯一一件事就是我使用的是 Java 1.5。 Java 1.5 的正则表达式引擎中是否有可能存在错误?假设它确实如此,我如何让 Java 1.5 做我想做的事情而不分解我的字符串并重新组装它?

编辑 我将 # 更改为 -- 运算符,因为看起来正则表达式会更复杂,使用两个字符而不是一个字符。我最初并没有透露我正在修改查询,以避免关于“你不应该那样修改查询!”的题外话讨论。我这样做是有充分理由的。请不要讨论查询修改的良好做法。谢谢

【问题讨论】:

  • 所以你想替换第三个例子中的@@ 而不是第二个例子?
  • 在 Java 正则表达式中,您不能将“有限多”长度或长度不明确的正则表达式提供给后视。某些语言甚至将其更多地限制为后视中的固定长度正则表达式。 .NET 是我所知道的唯一支持任意长度后视的。

标签: java regex regex-lookarounds


【解决方案1】:

你在这里真的不需要negative look-behind。你也可以不这样做。

应该是这样的:

String str = "I don't want to replace this @@";     
str = str.replaceAll("^([^#].*?)@@", "$1");

因此,它将字符串中不以# 开头的@@ 的第一次出现替换为@@ 之前的字符串部分。因此,@@ 被删除。这里replaceAll 有效,因为它使用了不情愿的量词 - .*?。所以,它会自动停在第一个@@


正如@nhahtdh 在评论中正确指出的那样,如果您的评论位于行尾,这可能会失败。所以,你可以使用这个:

String str = "I don't want to # replace this @@";
str = str.replaceAll("^([^#]*?)@@", "$1");

这个适用于任何情况。在给定的示例情况下,它不会替换 @@,因为它是评论的一部分。


如果您的评论开头由两个字符表示,则否定字符类将不起作用。您需要像这样使用negative look-ahead

String str = "This whole quote @@  is one big String -- asdf @@\n" +
             "-- I don't want to replace this @@\n" + 
             "But I want to replace this @@!";
str = str.replaceAll("(?m)^(((?!--).)*?)@@", "$1");

System.out.println(str);

输出:

This whole quote   is one big String -- asdf @@
-- I don't want to replace this @@
But I want to replace this !

模式开头的(?m)是用来开启MULTILINE模式的匹配,所以^会匹配每一行的开头,而不是整个表达式的开头。

【讨论】:

  • 这可能存在的唯一问题是一行:some text here #comment @@。不确定这是否会发生。
  • @nhahtdh。是的,这将是一个问题。让我们看看如何修改正则表达式。不错的收获:)
  • 我对我的问题进行了更改,因为我实际上使用两个字符作为评论开始而不是一个。这将如何改变正则表达式?
  • @JasonThompson。更新了答案。
  • 其实你并没有在替换字符串中使用$1。尝试:`.replaceAll("(?m)^((((?!--).)*?)@@", "$1foo")`` 。
【解决方案2】:

你可以这样使用:

String string = "This whole quote is one big String\n" +
                "# I don't want to replace this @@\n" +
                "And I also # don't want to replace this @@\n" +
                "But I want to replace this @@!\n" +
                "But not this @@!";

Matcher m =
    Pattern.compile (
        "^((?:[^@#]|@[^@]|#[^\n]*)*)@@", Pattern.MULTILINE).
            matcher (string);

StringBuffer result = new StringBuffer ();
if (m.find ())
    m.appendReplacement (result, "$1FOO");
m.appendTail (result);

System.out.println (result.toString ());

【讨论】:

    猜你喜欢
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-08
    • 2015-04-09
    • 1970-01-01
    • 2020-05-12
    相关资源
    最近更新 更多