多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
### [替换操作](https://lingcoder.gitee.io/onjava8/#/book/18-Strings?id=%e6%9b%bf%e6%8d%a2%e6%93%8d%e4%bd%9c) 正则表达式在进行文本替换时特别方便,它提供了许多方法: * `replaceFirst(String replacement)`以参数字符串`replacement`替换掉第一个匹配成功的部分。 * `replaceAll(String replacement)`以参数字符串`replacement`替换所有匹配成功的部分。 * `appendReplacement(StringBuffer sbuf, String replacement)`执行渐进式的替换,而不是像`replaceFirst()`和`replaceAll()`那样只替换第一个匹配或全部匹配。这是一个非常重要的方法。它允许你调用其他方法来生成或处理`replacement`(`replaceFirst()`和`replaceAll()`则只能使用一个固定的字符串),使你能够以编程的方式将目标分割成组,从而具备更强大的替换功能。 * `appendTail(StringBuffer sbuf)`在执行了一次或多次`appendReplacement()`之后,调用此方法可以将输入字符串余下的部分复制到`sbuf`中。 下面的程序演示了如何使用这些替换方法。开头部分注释掉的文本,就是正则表达式要处理的输入字符串: ~~~ // strings/TheReplacements.java import java.util.regex.*; import java.nio.file.*; import java.util.stream.*; /*! Here's a block of text to use as input to the regular expression matcher. Note that we first extract the block of text by looking for the special delimiters, then process the extracted block. !*/ public class TheReplacements { public static void main(String[] args) throws Exception { String s = Files.lines( Paths.get("TheReplacements.java")) .collect(Collectors.joining("\n")); // Match specially commented block of text above: Matcher mInput = Pattern.compile( "/\\*!(.*)!\\*/", Pattern.DOTALL).matcher(s); if(mInput.find()) s = mInput.group(1); // Captured by parentheses // Replace two or more spaces with a single space: s = s.replaceAll(" {2,}", " "); // Replace 1+ spaces at the beginning of each // line with no spaces. Must enable MULTILINE mode: s = s.replaceAll("(?m)^ +", ""); System.out.println(s); s = s.replaceFirst("[aeiou]", "(VOWEL1)"); StringBuffer sbuf = new StringBuffer(); Pattern p = Pattern.compile("[aeiou]"); Matcher m = p.matcher(s); // Process the find information as you // perform the replacements: while(m.find()) m.appendReplacement(sbuf, m.group().toUpperCase()); // Put in the remainder of the text: m.appendTail(sbuf); System.out.println(sbuf); } } /* Output: Here's a block of text to use as input to the regular expression matcher. Note that we first extract the block of text by looking for the special delimiters, then process the extracted block. H(VOWEL1)rE's A blOck Of tExt tO UsE As InpUt tO thE rEgUlAr ExprEssIOn mAtchEr. NOtE thAt wE fIrst ExtrAct thE blOck Of tExt by lOOkIng fOr thE spEcIAl dElImItErs, thEn prOcEss thE ExtrActEd blOck. */ ~~~ 此处使用上一章介绍过的[`Files`](https://lingcoder.gitee.io/onjava8/#/./17-Files)类打开并读入文件。`Files.lines()`返回一个`Stream`对象,包含读入的所有行,`Collectors.joining()`在每一行的结尾追加参数字符序列,最终拼接成一个`String`对象。 `mInput`匹配`/*!`和`!*/`之间的所有文字(注意分组的括号)。接下来,将存在两个或两个以上空格的地方,缩减为一个空格,并且删除每行开头部分的所有空格(为了使每一行都达到这个效果,而不仅仅是删除文本开头部分的空格,这里特意开启了多行模式)。这两个替换操作所使用的的`replaceAll()`是`String`对象自带的方法,在这里,使用此方法更方便。注意,因为这两个替换操作都只使用了一次`replaceAll()`,所以,与其编译为`Pattern`,不如直接使用`String`的`replaceAll()`方法,而且开销也更小些。 `replaceFirst()`只对找到的第一个匹配进行替换。此外,`replaceFirst()`和`replaceAll()`方法用来替换的只是普通字符串,所以,如果想对这些替换字符串进行某些特殊处理,这两个方法时无法胜任的。如果你想要那么做,就应该使用`appendReplacement()`方法。该方法允许你在执行替换的过程中,操作用来替换的字符串。在这个例子中,先构造了`sbuf`用来保存最终结果,然后用`group()`选择一个组,并对其进行处理,将正则表达式找到的元音字母替换成大些字母。一般情况下,你应该遍历执行所有的替换操作,然后再调用`appendTail()`方法,但是,如果你想模拟`replaceFirst()`(或替换n次)的行为,那就只需要执行一次替换,然后调用`appendTail()`方法,将剩余未处理的部分存入`sbuf`即可。 同时,`appendReplacement()`方法还允许你通过`\$g`直接找到匹配的某个组,这里的`g`就是组号。然而,它只能应付一些简单的处理,无法实现类似前面这个例子中的功能。