美文网首页
五分钟搞定Java正则表达式

五分钟搞定Java正则表达式

作者: 尔林 | 来源:发表于2019-05-26 23:49 被阅读0次

    1. 正则表达式的创建

    1.1 导入包:

    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    

    1.2 创建:

    //可以写成\d{3}-\d{3}-\d{4} 详情参见8
    Pattern pattern = Pattern.compile("\\d\\d\\d-\\d\\d\\d-\\d\\d\\d\\d");
    Matcher matcher = pattern.matcher("电话号码:444-555-6666 \n 电话号码:444-555-6669");
    

    1.3 取匹配值:

    while (matcher.find()) {
        System.out.println("start:"+matcher.start());//匹配到的开始位置
        System.out.println("e n d:"+matcher.end());//匹配到的结束位置
        System.out.println(matcher.group(0));//0为整个表达式结果
    }
    

    1.4 正则匹配结果输出:

    start:5
    e n d:17
    444-555-6666
    start:25
    e n d:37
    444-555-6669
    

    2. 正则表达式的括号分组

    2.1 创建分组:
    如果想要将区号从电话号中分离,添加括号就可以在正则表达式中创建“分组”:(\d\d\d)-(\d\d\d-\d\d\d\d)

    Pattern pattern = Pattern.compile("(\\d\\d\\d)-(\\d\\d\\d-\\d\\d\\d\\d)");
    Matcher matcher = pattern.matcher("电话号码:444-555-6666 \n 电话号码:444-555-6669");
    while (matcher.find()) {
        int count = matcher.groupCount();
        for(int i=1;i<=count;i++){//0是整个正则表达式的匹配结果,从1开始才是真正的分组结果
            System.out.println(matcher.group(i));
        }
    }
    

    2.2 正则匹配结果输出:

    444 //区号
    555-6666 //电话号
    444 //区号
    555-6669 //电话号
    

    3. 管道匹配多个分组

    3.1 "|"既是管道匹配符,管道匹配符匹配许多表达式中的一个时,就可以使用它。
    如:"gaierlin And erlin!" 要匹配gaierlin及erlin两个分组中的一个

    Pattern pattern = Pattern.compile("gaierlin|erlin");
    Matcher matcher = pattern.matcher("gaierlin And erlin!");
    while (matcher.find()) {
        System.out.println(matcher.group(0));
    }
    

    3.2 正则匹配结果输出:

    gaierlin
    erlin
    

    4. 问号实现可选匹配

    4.1 ?(问题)匹配零次或一次,如果想匹配的模式是可选的,则使用字符?表明它前面的分组在这个模式中是可选的。
    如:"电话号码:444-555-6666 \n 电话号码:555-6669",区号是可选项匹配,即(\d\d\d-),分组(\d\d\d-)出现零次或一次

    Pattern pattern = Pattern.compile("(\\d\\d\\d-)?\\d\\d\\d-\\d\\d\\d\\d");
    Matcher matcher = pattern.matcher("电话号码:444-555-6666 \n 电话号码:555-6669");
    while (matcher.find()) {
        System.out.println(matcher.group(0));
    }
    

    4.2 正则匹配结果输出:

    444-555-6666
    555-6669
    

    5. 星号匹配零次或多次

    5.1 (星号)匹配零次或多次,即星号之前的分组可以出现任意多次(零次或一次或二次或一次又一次)
    如:"love、lve、abc、loove、dbc、labcve、a9ve、abve、looooove",找出所有lo
    ve的所有内容。

    Pattern pattern = Pattern.compile("l(o)*ve");
    Matcher matcher = pattern.matcher("love、lve、abc、loove、dbc、labcve、a9ve、abve、looooove");
    while (matcher.find()) {
        System.out.println(matcher.group(0));
    }
    

    5.2 正则匹配结果输出:

    love
    lve
    loove
    looooove
    

    6. 加号匹配一次或多次

    6.1 +(加号)匹配一次或多次,即加号之前的分组可以出现至少一次。
    如:"love、lve、abc、loove、dbc、labcve、a9ve、abve、looooove",找出所有lo*ve的所有内容。

    Pattern pattern = Pattern.compile("l(o)+ve");
    Matcher matcher = pattern.matcher("love、lve、abc、loove、dbc、labcve、a9ve、abve、looooove");
    while (matcher.find()) {
        System.out.println(matcher.group(0));
    }
    

    6.2 正则匹配结果输出:

    love
    loove
    looooove
    

    7. 花括号匹配特定次数

    7.1 {}重复特定次数的分组:
    (love){,5}:代表重复0到5次
    (love){2,5}:代表重复2次到5次
    (love){5,}:代表重复5次到更多次

    如:"I you, I love you, I love love you, I love love love you, I love love love love you, I love love love love love you, I love love love love love love love love you!"

    Pattern pattern = Pattern.compile("I (love ){3,5}you");
    Matcher matcher = pattern.matcher("I you, I love you, I love love you, I love love love you, I love love love love you, I love love love love love you, I love love love love love love love love you!");
    while (matcher.find()) {
        System.out.println(matcher.group(0));
    }
    

    7.2 正则匹配结果输出:

    I love love love you
    I love love love love you
    I love love love love love you
    

    8. 字符分类

    8.1 在上面的实例中已经知道\d代表任意0-9的数字,像这样有缩写代码的如下表所示:只列出最常用的

    缩写分类 表示
    \d 0-9任意数字
    \D 除0-9的数字以外的任意字符
    \w 任意字母、数字、下划线字符
    \W 除字母、数字、下划线以外的任意字符
    \s 空格、制表符、回车换行符
    \S 除空格、制表符、回车换行符以外的任意字符

    再举号码:"电话号码:444-555-6666 \n 电话号码:444-555-6669"

    Pattern pattern = Pattern.compile("(\\d){3}-(\\d){3}-(\\d){4}");
    Matcher matcher = pattern.matcher("电话号码:444-555-6666 \\n 电话号码:444-555-6669");
    while (matcher.find()) {
        System.out.println(matcher.group(0));
    }
    

    8.2 正则匹配结果输出:

    444-555-6666
    444-555-6669
    

    9. 方括号自定义字符分类

    9.1 有时候\d \w \s等字符描述太宽泛,不能完成目标任务。
    如:检查文件命名是否合法(在文件命名中不允许出现?*|“<>:/字符),如果包含此类字符则不合法。
    此时就可以使用[]来自定义字符分类

    Pattern pattern = Pattern.compile("[?*|“<>:/]");
    Matcher matcher = pattern.matcher("abc*.txt");
    if(matcher.find()) {
        System.out.println("文件名不合法");
    }else {
        System.out.println("文件名合法");
    }
    

    9.2 正则匹配结果输出:

    文件名不合法
    

    注意:
    matches() 是拿整个输入的字符串和定义的正则模式匹配;
    find() 是包含匹配, 整个输入的字符串包含定义的正则模式;
    自行尝试下即可知道结果

    10. 通配字符

    10.1 .(句点)字符在正则表达式中称为“通配符”,它是除了回车换行符之外的所有字符都可以匹配。
    但是要记住通配字符只能匹配一个字符。
    如:"I love you! I lo0ve you! I loove you!"

    Pattern pattern = Pattern.compile("I (lo.ve) you");
    Matcher matcher = pattern.matcher("I love you! I lo0ve you! I loove you!");
    while (matcher.find()){
        System.out.println(matcher.group(0));
    }
    

    10.2 正则匹配结果输出:

    I lo0ve you
    I loove you
    

    11. 插入字符和美元字符

    11.1 ^(插入字符)表明匹配必须发生在被查找文本开始处。
    $(美元字符)表明匹配必须发生在被查找文本结束处。

    如:"Hello World" 分别用匹配"Hello"、"World$"及"Hello World$"

    Pattern pattern = Pattern.compile("^Hello");
    Matcher matcher = pattern.matcher("Hello World");
    while (matcher.find()){
        System.out.println(matcher.group(0));
    }
    

    11.2 正则匹配结果输出:

    Hello
    

    "World$"及"^Hello World$"请自行尝试

    12. 转义字符

    12.1 \ (反作)字符,即为转义字符
    如:"C+ C++"

    • 不添加\转义
    Pattern pattern = Pattern.compile("C++");
    Matcher matcher = pattern.matcher("C+ C++");
    while (matcher.find()){
        System.out.println(matcher.group(0));
    }
    

    正则匹配结果输出:

    C
    C
    
    • 添加\转义
    Pattern pattern = Pattern.compile("C\\+\\+");
    Matcher matcher = pattern.matcher("C+ C++");
    while (matcher.find()){
        System.out.println(matcher.group(0));
    }
    

    正则匹配结果输出:

    C++
    

    13. 用点-星匹配所有字符

    13.1 匹配所有字符串(.*)
    .(句点):通配符
    (星号):出现0次或多次
    所以(.
    )既是匹配所有字符,但是换行符要除外

    如:"First Name: gai LastName:erlin \n First Name: gai1 LastName:erlin1 \n First Name: g2ai LastName:2erlin"

    Pattern pattern = Pattern.compile("First Name: (.*) LastName:(.*)");
    Matcher matcher = pattern.matcher("First Name: gai LastName:erlin \n First Name: xxx LastName:erlin_xxx \n First Name: ooo LastName:xxx_erlin ");
    while (matcher.find()){
        System.out.println(matcher.group(0));
    }
    

    13.2 正则匹配结果输出:

    First Name: gai LastName:erlin 
    First Name: xxx LastName:erlin_xxx 
    First Name: ooo LastName:xxx_erlin
    

    14. 用句点字符匹配换行符

    14.1 在Pattern类中有

    public static Pattern compile(String regex, int flags)
    

    方法,参数flags:正则表达式的标记模式。
    所有标记模式如下表:

    编译标志 解释
    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'才被认作一行的中止,并且与'.','^',以及'$'进行匹配。

    14.2 跨多行匹配举例
    如:"abs \n start asdfkkie \nhello \naidnkd end" 要匹配start开始到end结束

    Pattern pattern = Pattern.compile("start (.*) end$",Pattern.DOTALL);
    Matcher matcher = pattern.matcher("abs \n start asdfkkie \nhello \naidnkd end");
    while (matcher.find()){
        System.out.println(matcher.group(0));
    }
    

    14.3 正则匹配结果输出:

    start asdfkkie 
    hello 
    aidnkd end
    

    14.4 不区分大小写举例:
    如:"gaierlin And erlin! GaiErLin And ErLIN!"

    Pattern pattern = Pattern.compile("(gai)*erlin",Pattern.CASE_INSENSITIVE);
    Matcher matcher = pattern.matcher("gaierlin And erlin! GaiErLin And ErLIN!");
    while (matcher.find()){
        System.out.println(matcher.group(0));
    }
    

    14.5 正则匹配结果输出:

    gaierlin
    erlin
    GaiErLin
    ErLIN
    

    14.6 不区分大小写且跨多行举例:
    如:"abs \n START asdfkkie \nhello \naidnkd END \nstart abc \n defg\n ffff end"

    public static Pattern compile(String regex, int flags)
    

    compile方法的flags只接受一个参数,如果要使用两个以上的标记编译正则怎么实现?
    答案是:使用|即:Pattern.CASE_INSENSITIVE|Pattern.DOTALL

    Pattern pattern = Pattern.compile("start (.*) end",Pattern.CASE_INSENSITIVE|Pattern.DOTALL);
    Matcher matcher = pattern.matcher("abs \\n START asdfkkie \\nhello \\naidnkd END \\n start abc \\n defg\\n ffff end");
    while (matcher.find()){
        System.out.println(matcher.group(0));
    }
    

    14.7 正则匹配结果输出:

    START asdfkkie \nhello \naidnkd END \n start abc \n defg\n ffff end
    

    15. 如何让别人更好的理解你所写的正则表达式

    15.1 如:javatianxia@163.com 验证邮箱为例

    Pattern pattern = Pattern.compile(
            "^\\w+(\\.\\w+)?" + //邮件登录名
            "\\@\\w+" +         //主机名
            "\\.(\\w+){2,4}"    //域名
    );
    Matcher matcher = pattern.matcher("javatianxia@163.com");
    if (matcher.matches()) {
        System.out.println("合法");
    } else {
        System.out.println("不合法");
    }
    

    看到这里想必都已经明白了,就是对正则表达式添加注释。

    15.2 正则匹配结果输出:

    合法
    

    相关文章

      网友评论

          本文标题:五分钟搞定Java正则表达式

          本文链接:https://www.haomeiwen.com/subject/vapqtctx.html