Java用正则表达式获取特征字符串

Posted 汪小哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java用正则表达式获取特征字符串相关的知识,希望对你有一定的参考价值。

1、正则表达式

正则表达式是一个非常高深的艺术、在编程过程中无论你写没有写过,时刻也使用过相关的工具 比如shell 中的一些常见的grep 、less 等等工具。

推荐一个非常好用的教程工具。
https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md

2、背景

很久之前,需要实现一个功能 从一个字符串中获取到 特征字符串,这里使用案号作为例子
(2020)浙0106民督28号-1
将上诉的案号信息 提取为如下的信息
caseCodeYear=2020
caseCodeCourtPronoun=浙0106
caseCodeTypePronoun=民督
caseCodeNumber=28

3、实现方案

3.1 java.lang.String#replaceAll

使用java.lang.String#replaceAll 中 获取regex 分组 $1 $2 $3 来进行获取 ,stackoverflow 中有个非常好玩的例子 https://stackoverflow.com/questions/36267354/java-string-replaceall-with-back-reference/36267574

@Test
public void getRegexReplace() 

    String regex = ".(\\\\d4).([\\\\u4e00-\\\\u9fa5]\\\\d0,4)([\\\\u4e00-\\\\u9fa5]0,5)(\\\\d+)号.*";

    String descStr = "(2020)浙0106民督28号-1";

    String caseCodeYear = descStr.replaceAll(regex, "$1");
    String caseCodeCourtPronoun = descStr.replaceAll(regex, "$2");
    String caseCodeTypePronoun = descStr.replaceAll(regex, "$3");
    String caseCodeNumber = descStr.replaceAll(regex, "$4");

    log.info("caseCodeYear= caseCodeCourtPronoun=,caseCodeTypePronoun=,caseCodeNumber=", caseCodeYear,
             caseCodeCourtPronoun, caseCodeTypePronoun, caseCodeNumber);

    //当然也可以一口气搞定 
    String allSpit = descStr.replaceAll(regex, "$1|$2|$3|$4");
    log.info("all split=",allSpit);

15:44:44.890 [main] INFO com.RegexExample - caseCodeYear=2020 caseCodeCourtPronoun=0106,caseCodeTypePronoun=民督,caseCodeNumber=28
15:44:44.924 [main] INFO com.RegexExample - all=2020|0106|民督|28

3.2 java.util.regex.Matcher#matches + java.util.regex.Matcher#groupCount

matches()是全部匹配,是将整个输入串与模式匹配 ,如果修改为 (2020)6浙0106民督28号-1 就不匹配了

@Test
public void getRegexByGroup() 
    String regex = ".(\\\\d4).([\\\\u4e00-\\\\u9fa5]\\\\d0,4)([\\\\u4e00-\\\\u9fa5]0,5)(\\\\d+)号.*";

    String caseCode = "(2020)浙0106民督28号-1";

    Pattern compile = Pattern.compile(regex);
    Matcher matcher = compile.matcher(caseCode);
    if (matcher.matches()) 
        for (int i1 = 0; i1 <= matcher.groupCount(); i1++) 
            log.info("group=,groupValue=", i1, matcher.group(i1));
        
    
 
15:36:13.466 [main] INFO com.RegexExample - group=0,groupValue=(2020)0106民督28-1
15:36:13.500 [main] INFO com.RegexExample - group=1,groupValue=2020
15:36:13.500 [main] INFO com.RegexExample - group=2,groupValue=0106
15:36:13.500 [main] INFO com.RegexExample - group=3,groupValue=民督
15:36:13.500 [main] INFO com.RegexExample - group=4,groupValue=28

3.3 java.util.regex.Matcher#find()+java.util.regex.Matcher#groupCount

find()方法是部分匹配,是查找输入串中与模式匹配的子串,如果该匹配的串有组还可以使用group()函数。
匹配的子串 的意思 可以存在多个相匹配的字符串。

3.3.1 正则匹配单个子串的例子

@Test
public void getRegexCodeFind1() 

    String regex = ".(\\\\d4).([\\\\u4e00-\\\\u9fa5]\\\\d0,4)([\\\\u4e00-\\\\u9fa5]0,5)(\\\\d+)号.*";

    String descStr = "(2020)浙0106民督28号-1";
    log.info(descStr.length() + "");

    Pattern compile = Pattern.compile(regex);
    Matcher matcher = compile.matcher(descStr);
    while (matcher.find()) 
        // INFO com.RegexExample - start=0 end=18
        log.info("start= end=", matcher.start(), matcher.end());

        for (int i1 = 0; i1 <= matcher.groupCount(); i1++) 
            log.info("group=,groupValue=", i1, matcher.group(i1));
        
    

15:38:55.381 [main] INFO com.RegexExample - 18
15:38:55.388 [main] INFO com.RegexExample - start=0 end=18
15:38:55.391 [main] INFO com.RegexExample - group=0,groupValue=(2020)0106民督28-1
15:38:55.391 [main] INFO com.RegexExample - group=1,groupValue=2020
15:38:55.391 [main] INFO com.RegexExample - group=2,groupValue=0106
15:38:55.391 [main] INFO com.RegexExample - group=3,groupValue=民督
15:38:55.391 [main] INFO com.RegexExample - group=4,groupValue=28

3.3.2 正则匹配多个的例子

@Test
public void getRegexCodeFind2() 

    String regex = "\\\\d=([^(,+)]*)";

    String desStr = "0=房源序号, 1=序号, 2=合同编号, 3=项目名称";
    log.info(desStr.length() + "");

    Pattern compile = Pattern.compile(regex);
    Matcher matcher = compile.matcher(desStr);
    while (matcher.find()) 
        // INFO com.RegexExample - start=0 end=18
        log.info("start= end=", matcher.start(), matcher.end());

        for (int i1 = 0; i1 <= matcher.groupCount(); i1++) 
            log.info("group=,groupValue=", i1, matcher.group(i1));
        
    


15:50:06.028 [main] INFO com.RegexExample - 30
15:50:06.033 [main] INFO com.RegexExample - start=1 end=7
15:50:06.035 [main] INFO com.RegexExample - group=0,groupValue=0=房源序号
15:50:06.035 [main] INFO com.RegexExample - group=1,groupValue=房源序号
15:50:06.035 [main] INFO com.RegexExample - start=9 end=13
15:50:06.035 [main] INFO com.RegexExample - group=0,groupValue=1=序号
15:50:06.036 [main] INFO com.RegexExample - group=1,groupValue=序号
15:50:06.036 [main] INFO com.RegexExample - start=15 end=21
15:50:06.036 [main] INFO com.RegexExample - group=0,groupValue=2=合同编号
15:50:06.036 [main] INFO com.RegexExample - group=1,groupValue=合同编号
15:50:06.036 [main] INFO com.RegexExample - start=23 end=29
15:50:06.036 [main] INFO com.RegexExample - group=0,groupValue=3=项目名称
15:50:06.036 [main] INFO com.RegexExample - group=1,groupValue=项目名称

4、stackoverflow 一个有趣的replaceall的问题

https://stackoverflow.com/questions/36267354/java-string-replaceall-with-back-reference/36267574

There is a Java Regex question: Given a string, if the " * " is at the start or the end of the string, keep it, otherwise, remove it. For example: 只保留前后的* 其他的去掉

@Test
public void stackoverflow() 
    String desStr = "**abc**def*";
    String $1$2 = desStr.replaceAll("(^\\\\*)|(\\\\*$)|\\\\*", "$1$2");
    log.info("$1$2 =", $1$2);

如何去验证这个打开 正则表达式的学习网址
https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md 然后学习跳转到具体的学习网址 输入这个表达式 (^\\)|(\\$)|\\* 可以简单的理解,匹配第一个是* 或者 最后一个是* 或者 中间是* 的字符串,然后通过group1 group2 的值去替换匹配到的group的值的信息。

4.1 验证一下每次group 匹配到的是什么?

@Test
public void stackoverflow1() 

    String regex = "(^\\\\*)|(\\\\*$)|\\\\*";

    String desStr = "**abc**def*";

    Pattern compile = Pattern.compile(regex);
    Matcher matcher = compile.matcher(desStr);
    while (matcher.find()) 
        // INFO com.RegexExample - start=0 end=18
        log.info("start= end=", matcher.start(), matcher.end());

        for (int i1 = 0; i1 <= matcher.groupCount(); i1++) 
            log.info("group=,groupValue=", i1, matcher.group(i1));
        
    

从下面的数据分析一下:group=0 可以忽略这个就是当前group组的全部数据;
在前面的* ,匹配到的时候 总会有 group2 数据为空 =>replace 为一个*
最后面的* ,匹配到的时候 总会有 group1 数据为空 => replace 为一个*
中间匹配到的* 匹配到的时候 总会有 group1 group2 数据为空 =>replace 为空
如此 刚刚好解释了上面的一个问题。

16:11:45.754 [main] INFO com.RegexExample - start=0 end=1
16:11:45.767 [main] INFO com.RegexExample - group=0,groupValue=*
16:11:45.767 [main] INFO com.RegexExample - group=1,groupValue=*
16:11:45.767 [main] INFO com.RegexExample - group=2,groupValue=null
    
16:11:45.767 [main] INFO com.RegexExample - start=1 end=2
16:11:45.767 [main] INFO com.RegexExample - group=0,groupValue=*
16:11:45.767 [main] INFO com.RegexExample - group=1,groupValue=null
16:11:45.767 [main] INFO com.RegexExample - group=2,groupValue=null
    
16:11:45.767 [main] INFO com.RegexExample - start=5 end=6
16:11:45.768 [main] INFO com.RegexExample - group=0,groupValue=*
16:11:45.768 [main] INFO com.RegexExample - group=1,groupValue=null
16:11:45.768 [main] INFO com.RegexExample - group=2,groupValue=null
    
16:11:45.768 [main] INFO com.RegexExample - start=6 end=7
16:11:45.768 [main] INFO com.RegexExample - group=0,groupValue=*
16:11:45.768 [main] INFO com.RegexExample - group=1,groupValue=null
16:11:45.768 [main] INFO com.RegexExample - group=2,groupValue=null
    
16:11:45.768 [main] INFO com.RegexExample - start=10 end=11
16:11:45.768 [main] INFO com.RegexExample - group=0,groupValue=*
16:11:45.768 [main] INFO com.RegexExample - group=1,groupValue=null
16:11:45.768 [main] INFO com.RegexExample - group=2,groupValue=*

以上是关于Java用正则表达式获取特征字符串的主要内容,如果未能解决你的问题,请参考以下文章

java用正则表达式截取json多余的字符串

QRegExp 正则表达式详解

Linux 学习总结(84)—— 回顾下正则表达式

Linux 学习总结(84)—— 回顾下正则表达式

正则表达式相关笔记

正则表达式