JAVA 正则表达式教程(超详细)三(续)

2019-03-16 19:09|来源: 陈广佳

匹配的模式(Pattern flags)

compile( )方法还有一个版本,它需要一个控制正则表达式的匹配行为的参数:

Pattern Pattern.compile(String regex, int flag)
flag的取值范围如下:
编译标志效果
Pattern.CANON_EQ当且仅当两个字符的"正规分解(canonical decomposition)"都完全相同的情况下,才认定匹配。比如用了这个标志之后,表达式"a/u030A"会匹配"?"。默认情况下,不考虑"规范相等性(canonical equivalence)"。
Pattern.CASE_INSENSITIVE
(?i)
默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。这个标志能让表达式忽略大小写进行匹配。要想对Unicode字符进行大小不明感的匹配,只要将UNICODE_CASE与这个标志合起来就行了。
Pattern.COMMENTS
(?x)
在这种模式下,匹配时会忽略(正则表达式里的)空格字符(注:不是指表达式里的"//s",而是指表达式里的空格,tab,回车之类)。注释从#开始,一直到这行结束。可以通过嵌入式的标志来启用Unix行模式。
Pattern.DOTALL
(?s)
在这种模式下,表达式'.'可以匹配任意字符,包括表示一行的结束符。默认情况下,表达式'.'不匹配行的结束符。
Pattern.MULTILINE
(?m)
在这种模式下,'^'和'$'分别匹配一行的开始和结束。此外,'^'仍然匹配字符串的开始,'$'也匹配字符串的结束。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。
Pattern.UNICODE_CASE
(?u)
在这个模式下,如果你还启用了CASE_INSENSITIVE标志,那么它会对Unicode字符进行大小写不明感的匹配。默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。
Pattern.UNIX_LINES
(?d)
在这个模式下,只有'/n'才被认作一行的中止,并且与'.','^',以及'$'进行匹配。

在这些标志里面,Pattern.CASE_INSENSITIVEPattern.MULTILINE,以及Pattern.COMMENTS是最有用的(其中Pattern.COMMENTS还能帮我们把思路理清楚,并且/或者做文档)。注意,你可以用在表达式里插记号的方式来启用绝大多数的模式。这些记号就在上面那张表的各个标志的下面。你希望模式从哪里开始启动,就在哪里插记号。

可以用"OR" ('|')运算符把这些标志合使用:

//: c12:ReFlags.java
import java.util.regex.*;
import com.bruceeckel.simpletest.*;
public class ReFlags {
    private static Test monitor = new Test();
    public static void main(String[] args) {
          Pattern p =  Pattern.compile("^java",
                     Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
        Matcher m = p.matcher(
               "java has regex/nJava has regex/n" +
        "JAVA has pretty good regular expressions/n" +
        "Regular expressions are in Java");
    while(m.find())
        System.out.println(m.group());
    monitor.expect(new String[] {
        "java","Java","JAVA"});
    }
} ///:~

这样创建出来的正则表达式就能匹配以"java","Java","JAVA"...开头的字符串了。此外,如果字符串分好几行,那它还会对每一行做匹配(匹配始于字符序列的开始,终于字符序列当中的行结束符)。注意,group( )方法仅返回匹配的部分。

split( )

所谓分割是指将以正则表达式为界,将字符串分割成String数组。

String[] split(CharSequence charseq)
String[] split(CharSequence charseq, int limit)

这是一种既快又方便地将文本根据一些常见的边界标志分割开来的方法。

//: c12:SplitDemo.java
import java.util.regex.*;
import com.bruceeckel.simpletest.*;
import java.util.*;
public class SplitDemo {
    private static Test monitor = new Test();
    public static void main(String[] args) {
        String input = "This!!unusual use!!of exclamation!!points";
        System.out.println(Arrays.asList( 
            Pattern.compile("!!").split(input)));
        // Only do the first three:
         System.out.println(Arrays.asList(
            Pattern.compile("!!").split(input, 3)));
        System.out.println(Arrays.asList(
            "Aha! String has a split() built in!".split(" ")));
        monitor.expect(new String[] {
            "[This, unusual use, of exclamation, points]",
            "[This, unusual use, of exclamation!!points]",
            "[Aha!, String, has, a, split(), built, in!]"
        });
    }
} ///:~

第二个split( )会限定分割的次数。

正则表达式是如此重要,以至于有些功能被加进了String类,其中包括split( )(已经看到了),matches( )replaceFirst( )以及replaceAll( )。这些方法的功能同PatternMatcher的相同。

替换操作

正则表达式在替换文本方面特别在行。下面就是一些方法:

replaceFirst(String replacement)将字符串里,第一个与模式相匹配的子串替换成replacement

replaceAll(String replacement),将输入字符串里所有与模式相匹配的子串全部替换成replacement

appendReplacement(StringBuffer sbuf, String replacement)sbuf进行逐次替换,而不是像replaceFirst( )replaceAll( )那样,只替换第一个或全部子串。这是个非常重要的方法,因为它可以调用方法来生成replacement(replaceFirst( )replaceAll( )只允许用固定的字符串来充当replacement)。有了这个方法,你就可以编程区分group,从而实现更强大的替换功能。

调用完appendReplacement( )之后,为了把剩余的字符串拷贝回去,必须调用appendTail(StringBuffer sbuf, String replacement)

下面我们来演示一下怎样使用这些替换方法。说明一下,这段程序所处理的字符串是它自己开头部分的注释,是用正则表达式提取出来并加以处理之后再传给替换方法的。

//: c12:TheReplacements.java
import java.util.regex.*;
import java.io.*;
import com.bruceeckel.util.*;
import com.bruceeckel.simpletest.*;
/*! Here's a block of text to use as input to
    the regular expression matcher. Note that we'll
    first extract the block of text by looking for
    the special delimiters, then process the
    extracted block. !
*/
public class TheReplacements {
    private static Test monitor = new Test();
    public static void main(String[] args) throws Exception {
        String s = TextFile.read("TheReplacements.java");
        // Match the 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 one or more 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);
        monitor.expect(new String[]{
            "Here's a block of text to use as input to",
            "the regular expression matcher. Note that we'll",
            "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'll",
            "fIrst ExtrAct thE blOck Of tExt by lOOkIng fOr",
            "thE spEcIAl dElImItErs, thEn prOcEss thE",
            "ExtrActEd blOck. "
        });
    }
} ///:~

TextFile.read( )方法来打开和读取文件。mInput的功能是匹配'/*!' 和 '!*/' 之间的文本(注意一下分组用的括号)。接下来,我们将所有两个以上的连续空格全都替换成一个,并且将各行开头的空格全都去掉(为了让这个正则表达式能对所有的行,而不仅仅是第一行起作用,必须启用多行模式)。这两个操作都用了StringreplaceAll( )(这里用它更方便)。注意,由于每个替换只做一次,因此除了预编译Pattern之外,程序没有额外的开销。

replaceFirst( )只替换第一个子串。此外,replaceFirst( )replaceAll( )只能用常量(literal)来替换,所以如果每次替换的时候还要进行一些操作的话,它们是无能为力的。碰到这种情况,得用appendReplacement( ),它能在进行替换的时候想写多少代码就写多少。在上面那段程序里,创建sbuf的过程就是选group做处理,也就是用正则表达式把元音字母找出来,然后换成大写的过程。通常你得在完成全部的替换之后才调用appendTail( ),但是如果要模仿replaceFirst( )(或"replace n")的效果,你也可以只替换一次就调用appendTail( )。它会把剩下的东西全都放进sbuf

你还可以在appendReplacement( )replacement参数里用"$g"引用已捕获的group,其中'g' 表示group的号码。不过这是为一些比较简单的操作准备的,因而其效果无法与上述程序相比。

reset( )

此外,还可以用reset( )方法给现有的Matcher对象配上个新的CharSequence

//: c12:Resetting.java
import java.util.regex.*;
import java.io.*;
import com.bruceeckel.simpletest.*;
publicclass Resetting {
    private static Test monitor = new Test();
    public static void main(String[] args) throws Exception {
        Matcher m = Pattern.compile("[frb][aiu][gx]")
                   .matcher("fix the rug with bags");
        while(m.find())
            System.out.println(m.group());
        m.reset("fix the rig with rags");
        while(m.find())
            System.out.println(m.group());
        monitor.expect(new String[]{
            "fix",
            "rug",
            "bag",
            "fix",
            "rig",
            "rag"
        });
    }
} ///:~

JAVA 正则表达式教程(超详细)四(续)

相关问答

更多
  • 正则表达式的主要用法就是判断某个字符串是否符合某个固定的格式,以下是电话号码的格式判断: BufferedReader in;   Pattern pattern = Pattern.compile("//(//d{3}//)//s//d{3}-//d{4}");   in = new BufferedReader(new FileReader("18046521658"));   String s;   while ((s = in.readLine()) != null)   {   Matcher m ...
  • java.util.regex.Pattern返回由此匹配器解释的模式 java.util.regex.Matches ###regex里没有Matcher方法 尝试将整个区域与模式匹配。 如果匹配成功,则可以通过 start、end 和 group 方法获取更多信息。 返回: 当且仅当整个区域序列匹配此匹配器的模式时才返回 true。
  • java正则表达式[2023-08-29]

    ^ 和 $ 他们是分别用来匹配字符串的开始和结束,以下分别举例说明: "^The": 开头一定要有"The"字符串; "of despair$": 结尾一定要有"of despair" 的字符串; 那么, "^abc$": 就是要求以abc开头和以abc结尾的字符串,实际上是只有abc匹配。 "notice": 匹配包含notice的字符串。 你可以看见如果你没有用我们提到的两个字符(最后一个例子),就是说 模式(正则表达式) 可以出现在被检验字符串的任何地方,你没有把他锁定到两边。 接着,说说 '*', ...
  • http://www.ccw.com.cn/htm/app/aprog/01_7_31_4.asp 内容太多,不写了,自己去看看吧
  • 给我邮箱,我发一份资料给你,是关于正则表达式的基础,也算挺详细的!
  • package com; public class Joey { public static void main(String[] args) { String ip = "10.1.107.0/24"; String reg = "^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)/\\d+$"; System.out.println(ip.matches(reg)); } }
  • java正则表达式[2022-01-30]

    ^ 和 $ 他们是分别用来匹配字符串的开始和结束,以下分别举例说明: "^The": 开头一定要有"The"字符串; "of despair$": 结尾一定要有"of despair" 的字符串; 那么, "^abc$": 就是要求以abc开头和以abc结尾的字符串,实际上是只有abc匹配。 "notice": 匹配包含notice的字符串。 你可以看见如果你没有用我们提到的两个字符(最后一个例子),就是说 模式(正则表达式) 可以出现在被检验字符串的任何地方,你没有把他锁定到两边。 接着,说说 '*', ...
  • 就是检查字符串是否符合某个格式 看我的例子 public class Judge { public static void main(String[] args) { String a="\\w{0,}\\@?\\w{0,}\\.{1,}\\w{0,}"; String str1="aaaa@"; String str2="aaaa"; String str3="aaaaa@111.com"; if(str1.matches(a)){ System.out.println(str1+"是1个E—mail地址 ...