如何从含连续重复字符的字符串中仅保留指定数量的重复字符?
嘿,这个问题我之前刚折腾过!你现在的写法只能固定N=2,核心原因是把正则里的重复次数和替换字符串都写死了,只要改成动态生成正则和替换内容,就能适配任意N值啦,我给你两种解决方案:
方法一:用动态生成的正则+replaceAll(简洁高效)
这种方法完美匹配你的需求,思路是:只匹配那些连续重复次数超过N的字符序列,然后把它们替换成正好N个该字符,而重复次数不足N的序列会被保留原样。
代码示例:
int N = 3; // 你可以改成任意非负整数,比如0、1、4等 String input = "fffooooobbbbaarrr"; // 动态构建正则:匹配一个字符后面跟至少N个相同字符(总长度≥N+1) String regex = String.format("(\\w)\\1{%d,}", N); // 动态构建替换字符串:重复N次捕获到的字符 String replacement = new String(new char[N]).replace("\0", "$1"); String result = input.replaceAll(regex, replacement); System.out.println(result); // 输出:fffooobbbaarrr
逻辑拆解:
- 正则
(\\w)\\1{N,}:(\\w)捕获单个单词字符,\\1{N,}表示这个字符至少重复N次,所以整个匹配的是连续N+1个及以上的相同字符。 - 替换字符串是N个
$1(也就是捕获到的字符重复N次),这样就把超长的重复序列截断成正好N个,而短序列不会被匹配,自然保留原样。 - 特殊情况处理:
- 当N=0时,替换字符串是空,正则会匹配所有连续字符(包括单个字符),最终输出空字符串。
- 当N=1时,正则匹配连续2个及以上的相同字符,替换成单个字符,正好得到
fobar。
方法二:用Matcher自定义替换(更灵活)
如果你需要处理非单词字符(比如空格、符号),或者想更精细控制替换逻辑,可以用Matcher的appendReplacement方法,逐个处理每个匹配到的连续字符序列:
int N = 2; String input = "fffooooobbbbaarrr"; // 匹配任意连续重复的单词字符,改成"(.\\1*)"可以匹配所有字符 Pattern pattern = Pattern.compile("(\\w)\\1*"); Matcher matcher = pattern.matcher(input); StringBuffer resultSb = new StringBuffer(); while (matcher.find()) { String matchedSeq = matcher.group(); // 取序列的前N个字符,如果序列长度小于N就取全部 String replacement = matchedSeq.substring(0, Math.min(matchedSeq.length(), N)); // 注意用quoteReplacement避免替换字符串里的特殊字符生效 matcher.appendReplacement(resultSb, Matcher.quoteReplacement(replacement)); } matcher.appendTail(resultSb); System.out.println(resultSb.toString()); // 输出:ffoobbaarr
这种方法的好处是不依赖正则的量词逻辑,直接根据匹配到的序列长度动态生成替换内容,适用性更广。
为什么你原来的写法只能固定N=2?
你之前写的Pattern.compile("(\\w)\\1{2,}")和replaceAll("$1$1")都是写死了“匹配连续3个及以上的字符,替换成2个”,把其中的数字换成动态生成的N值,问题就解决啦~
内容的提问来源于stack exchange,提问作者anta40
相关产品推荐
相关产品推荐

