使用Java正则表达式在字符串中删除每个字符。

10

我有一个作业问题,需要使用正则表达式从字符串中删除每隔一个字符的内容。

其中一部分要求我删除索引为1、3、5...的字符。我已按以下方式完成:

String s = "1a2b3c4d5";
System.out.println(s.replaceAll("(.).", "$1"));

这将打印出12345,这正是我想要的。本质上,我每次匹配两个字符,并用第一个字符替换掉它们。我使用了组捕获来实现这一点。

问题是,我在完成作业的第二部分时遇到了麻烦,需要删除索引为0、2、4、...的字符。

我已经做了以下操作:

String s = "1a2b3c4d5";
System.out.println(s.replaceAll(".(.)", "$1"));

这将打印出abcd5,但正确的答案应该是abcd。我的正则表达式只在输入字符串长度为奇数时才不正确。如果长度为偶数,则正则表达式可以正常工作。

我认为我离答案很接近,但不确定如何修复它。


我不太确定是否可以将此作为答案发布,也无法测试它,但我想知道是否插入一个?量词是否有效?也就是说,类似于 System.out.println(s.replaceAll(".(.)?", "$1")); (编辑:我讨厌自己是对的而不确定!) - Platinum Azure
3个回答

20
您的答案非常接近:只需将第二个字符匹配设为可选。
String s = "1a2b3c4d5";
System.out.println(s.replaceAll(".(.)?", "$1"));
// prints "abcd"

这能够正常工作,因为:
  • 正则表达式默认具有贪婪性,如果第二个字符存在,则将其匹配
    • 当输入长度为奇数时,在最后一次替换中第二个字符将不存在,但仍会匹配一个字符(即输入的最后一个字符)。
  • 即使组未匹配成功,您仍可以在替换中使用反向引用
    • 它将替换为空字符串,而不是"null"
    • 这与Matcher.group(int)不同,后者对于失败的组返回null

参考资料


仔细研究第一部分

让我们仔细研究作业的第一部分:

String s = "1a2b3c4d5";
System.out.println(s.replaceAll("(.).", "$1"));
// prints "12345"

在这里,你不必使用?进行第二个字符的匹配,但它“起作用”的原因是,即使你没有匹配最后一个字符,你也不必!由于问题规范,最后一个字符可以保持未匹配、未替换。

现在假设我们想要删除索引为1、3、5...的字符,并将索引为0、2、4...的字符放入括号中。

String s = "1a2b3c4d5";
System.out.println(s.replaceAll("(.).", "($1)"));
// prints "(1)(2)(3)(4)5"

啊哈!! 现在您遇到了奇数长度输入的完全相同的问题! 您无法使用正则表达式匹配最后一个字符,因为您的正则表达式需要两个字符,但奇数长度输入末尾只有一个字符!

解决方案是再次使第二个字符匹配变为可选:

String s = "1a2b3c4d5";
System.out.println(s.replaceAll("(.).?", "($1)"));
// prints "(1)(2)(3)(4)(5)"

1
我还没有测试过这个,但是你的作业第一部分适用于偶数和奇数吗?出于同样的原因,你可能也需要在第一部分进行修复。不过我不太确定。 - corsiKa
@glowcoder:很好的评论!多亏了你的提醒,我更深入地研究了第一部分! - polygenelubricants

2

只有在输入字符串长度为奇数时,我的正则表达式才会出错。如果是偶数,则我的正则表达式可以正常工作。

将您的表达式更改为.(.)?——问号使第二个字符变成可选项,这意味着输入是奇数还是偶数并不重要。


0

你的正则表达式需要2个字符才能匹配,因此在最后一个字符上失败了。

这个正则表达式:

".(.{0,1})"

将第二个字符设为可选,这样它就可以与你的最终“5”匹配


3
{0,1} 不就是用来替代 ? 的一种混淆而无必要的写法吗? - Matt
这是一种不同的写法,但我认为它会造成困惑并且不必要。 - tim_yates
请参见https://dev59.com/RXA75IYBdhLWcg3w7tt6 - polygenelubricants

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接