首页 > 解决方案 > Java正则表达式:用`+`替换所有字符,给定字符串的实例除外

问题描述

我有以下问题

用符号替换字符串中的所有字符,+方法中给定字符串的实例除外

因此,例如,如果给定的字符串是abc123efg并且他们希望我替换除每个实例之外的每个字符,123那么它将变为+++123+++.

我认为正则表达式可能是最好的,我想出了这个。

str.replaceAll("[^str]","+") 

其中 str 是一个变量,但它不允许我使用该方法而不将其放在引号中。如果我只想替换变量字符串 str 我该怎么做?我用手动输入的字符串运行它,它适用于该方法,但我可以只输入一个变量吗?

截至目前,我相信它正在寻找字符串“str”而不是变量字符串。

这是除两种情况外的许多情况下的正确输出:(

在此处输入图像描述

开放测试用例列表:

plusOut("12xy34", "xy") → "++xy++"
plusOut("12xy34", "1") → "1+++++"
plusOut("12xy34xyabcxy", "xy") → "++xy++xy+++xy"
plusOut("abXYabcXYZ", "ab") → "ab++ab++++"
plusOut("abXYabcXYZ", "abc") → "++++abc+++"
plusOut("abXYabcXYZ", "XY") → "++XY+++XY+"
plusOut("abXYxyzXYZ", "XYZ") → "+++++++XYZ"
plusOut("--++ab", "++") → "++++++"
plusOut("aaxxxxbb", "xx") → "++xxxx++"
plusOut("123123", "3") → "++3++3"

标签: javaregex

解决方案


看起来这是plusOutCodingBat 上的问题。

我有 3 个解决这个问题的方法,并写了一个新的流媒体解决方案只是为了好玩。

解决方案1:循环检查

从输入字符串中创建一个 StringBuilder,并检查每个位置的单词。如果不匹配则替换字符,如果找到则跳过单词的长度。

public String plusOut(String str, String word) {
  StringBuilder out = new StringBuilder(str);

  for (int i = 0; i < out.length(); ) {
    if (!str.startsWith(word, i))
      out.setCharAt(i++, '+');
    else
      i += word.length();
  }

  return out.toString();
}

这可能是初学者程序员的预期答案,尽管假设该字符串不包含任何星体平面字符,该字符将由 2 个字符而不是 1 表示。

解决方案2:用标记替换单词,替换其余部分,然后恢复单词

public String plusOut(String str, String word) {
    return str.replaceAll(java.util.regex.Pattern.quote(word), "@").replaceAll("[^@]", "+").replaceAll("@", word);
}

不是一个合适的解决方案,因为它假定某个字符或字符序列没有出现在字符串中。

注意使用Pattern.quote来防止wordreplaceAll方法解释为正则表达式语法。

解决方案 3:正则表达式\G

public String plusOut(String str, String word) {
  word = java.util.regex.Pattern.quote(word);
  return str.replaceAll("\\G((?:" + word + ")*+).", "$1+");
}

构造 regex \G((?:word)*+).,它或多或少地做了解决方案 1 正在做的事情:

  • \G确保比赛从上一场比赛结束的地方开始
  • ((?:word)*+)挑选出 0 个或多个word- 如果有的话,这样我们就可以用 . 替换它们$1。这里的关键是所有格量词*+,它强制正则表达式保留word它找到的任何实例。word否则,当出现在字符串末尾时,正则表达式将无法正常工作,因为正则表达式回溯以匹配.
  • .不会是 any 的一部分word,因为前一部分已经挑选出所有连续出现的word并且不允许回溯。我们将替换为+

解决方案 4:流式传输

public String plusOut(String str, String word) {
  return String.join(word, 
    Arrays.stream(str.split(java.util.regex.Pattern.quote(word), -1))
      .map((String s) -> s.replaceAll("(?s:.)", "+"))
      .collect(Collectors.toList()));
}

这个想法是将字符串拆分为word,对其余部分进行替换,然后word使用 usingString.join方法将它们连接回来。

  • 和上面一样,我们需要Pattern.quote避免split解释wordas 正则表达式。由于split默认情况下会删除数组末尾的空字符串,因此我们需要-1在第二个参数中使用以split保留这些空字符串。
  • 然后我们从数组中创建一个流,并将其余的替换为+. 在 Java 11 中,我们可以s -> String.repeat(s.length())改用。
  • 剩下的只是将 Stream 转换为 Iterable (在本例中为 List )并加入它们以获得结果

推荐阅读