java - 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"
解决方案
看起来这是plusOut
CodingBat 上的问题。
我有 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
来防止word
被replaceAll
方法解释为正则表达式语法。
解决方案 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
解释word
as 正则表达式。由于split
默认情况下会删除数组末尾的空字符串,因此我们需要-1
在第二个参数中使用以split
保留这些空字符串。 - 然后我们从数组中创建一个流,并将其余的替换为
+
. 在 Java 11 中,我们可以s -> String.repeat(s.length())
改用。 - 剩下的只是将 Stream 转换为 Iterable (在本例中为 List )并加入它们以获得结果
推荐阅读
- unit-testing - asp net core 单元测试模型验证器未涵盖非必填字段
- python-3.x - Python3 - np.histogram 输出十进制问题
- javascript - JS 在 for 中使用 push 并应用 toUpperCase
- flutter - 非常动态和动画的 Listview 与 Stream
- cluster-computing - centos7.4上安装Ambari服务器出现repos错误
- c - 如何从带有分隔符的文本文件中扫描字符串然后显示它?
- arrays - 我正在制作一个菜单驱动程序,我必须在其中创建、删除和插入一个数组
- c# - 如何为可执行应用程序创建 Windows 服务?
- phpmyadmin - ubuntu 云服务器上的 phpmyadmin
- python - 如何以这种方式扩展字典?