正则表达式的预编译功能

正则表达式的预编译功能


在阿里巴巴开发手册中规定如下:
【强制】在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。
说明: 不要在方法体内 定义: Pattern pattern = Pattern.compile(规则);

(1)在IDEA中尝试这段代码,看会出现什么提示?

 public void t(){
        Pattern pattern = Pattern.compile(".*:(.*)://.*/(.*)\\?.*$");
    }

在这里插入图片描述
(2)打开阿里巴巴违约插件后提示的代码:

public class XxxClass {
        // Use precompile  使用预编译
        private static Pattern NUMBER_PATTERN = Pattern.compile("[0-9]+");
        
        public Pattern getNumberPattern() {
            // Avoid use Pattern.compile in method body.   避免使用这种方式在 方法中
            Pattern localPattern = Pattern.compile("[0-9]+");
            return localPattern;
        }
    }

说明:插件提示的意思是 不要在方法体内定义,让我们把这个信息抽取到方法外面使其触发预编译。

Pattern用法

  • java.util.regex.Pattern (摘自sun主页) , Implements: 实现了Serializable接口
  • Pattern类用于创建一个正则表达式,也可以说是创建一个匹配模式,可以通过两个静态方法创建:compile(String regex)和compile(String regex,int flags),其中regex是正则表达式,flags为可选模式(如:Pattern.CASE_INSENSITIVE 忽略大小写)
  • Pattern complie(String regex):编译正则表达式,并创建Pattern类
  • 由于Pattern的构造函数是私有的,不可以直接创建,所以通过静态的简单工厂方法compile(String regex)方法来创建,将给定的正则表达式编译并赋予给Pattern类
  • Pattern compile(String regex, int flags) , flag参数用来控制正则表达式的匹配行为,可取值范围如下:
  • (1)Pattern.CANON_EQ:启用规范等价。当且仅当两个字符的“正规分解(canonicaldecomposition)”都完全相同的情况下,才认定匹配。默认情况下,不考虑“规范相等性(canonical equivalence)”。

(2)Pattern.CASE_INSENSITIVE:启用不区分大小写的匹配。默认情况下,大小写不敏感的匹配只适用于US-ASCII字符集。这个标志能让表达式忽略大小写进行匹配,要想对Unicode字符进行大小不敏感的匹配,只要将UNICODE_CASE与这个标志合起来就行了。

(3)Pattern.COMMENTS:模式中允许空白和注释。在这种模式下,匹配时会忽略(正则表达式里的)空格字符(不是指表达式里的“\s”,而是指表达式里的空格,tab,回车之类)。注释从#开始,一直到这行结束。可以通过嵌入式的标志来启用Unix行模式。

(4)Pattern.DOTALL:启用dotall模式。在这种模式下,表达式‘.’可以匹配任意字符,包括表示一行的结束符。默认情况下,表达式‘.’不匹配行的结束符。

(5)Pattern.LITERAL:启用模式的字面值解析。

(6)Pattern.MULTILINE:启用多行模式。在这种模式下,‘^’和‘ ’ 分 别 匹 配 一 行 的 开 始 和 结 束 。 此 外 , ‘ ’ 仍 然 匹 配 字 符 串 的 开 始 , ‘ ’分别匹配一行的开始和结束。此外,‘^’仍然匹配字符串的开始,‘ ’也匹配字符串的结束。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。

(7)Pattern.UNICODE_CASE:启用Unicode感知的大小写折叠。在这个模式下,如果你还启用了CASE_INSENSITIVE标志,那么它会对Unicode字符进行大小写不敏感的匹配。默认情况下,大小写不敏感的匹配只适用于US-ASCII字符集。

(8)Pattern.UNIX_LINES:启用Unix行模式。在这个模式下,只有‘\n’才被认作一行的中止,并且与‘.’、‘^’、以及‘$’进行匹配。

  • 指定为字符串的正则表达式必须首先被编译为此类的实例。然后,可将得到的模式用于创建 Matcher 对象,依照正则表达式,该对象可以与任意 字符序列 匹配。执行匹配所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一模式。
  • Pattern p = Pattern.compile(“a*b”);
    Matcher m = p.matcher(“aaaaab”);
    boolean b = m.matches();
  • 在仅使用一次正则表达式时,可以方便地通过此类定义 Matcher 方法。此方法编译表达式并在单个调用中将输入序列与其匹配。语句
  • boolean b = Pattern.matches(“a*b”, “aaaaab”);
  • 此类的实例是不可变的,可供多个并发线程安全使用 ,Matcher类的实例用于此目的则不安全
  • Pattern类还有两个根据匹配模式拆分输入序列的方法:split(CharSequence input) 和split(CharSequence input, int limit),其中limit为返回元素的个数
  • Pattern pattern = Pattern.compile(“Java”);
    String test=“123Java456Java789Java”;
    String[] result = pattern.split(test);
    for(String s : result)
    // 输出123 456 789
    System.out.println(s);

【错误示例】

// 没有使用预编译
private void function(...) {
if (Pattern.matches(regexRule, content)) {
...

     }
}

// 多次预编译
private void function(...) {
Pattern pattern = Pattern.compile(regexRule);
Matcher m = pattern.matcher(content);

if (m.matches()) {
...

}

matcher用法

public boolean matcher()
参数:此方法不带任何参数。
返回值:此方法返回一个布尔值,该值显示此模式是否与此匹配器匹配。
    
Matcher类了,Pattern类中的matcher(CharSequence input)会返回一个Matcher对象
Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持,要想得到更丰富的正则匹配操作,那就需要将Pattern与Matcher联合使用
Matcher类提供了三个返回boolean值得匹配方法:matches(),lookingAt(),find(),find(int start),其中matches()用于全字符串匹配,lookingAt从字符串最开头开始匹配满足的子串,find可以对任意位置字符串匹配,其中start为起始查找索引值。
    
实例:
Pattern pattern = Pattern.compile("Java");
        String test1 = "Java";
        String test2 = "Java12345";
        String test3 = "12345Java";
        
        //matches()用于全字符串匹配
        Matcher matcher = pattern.matcher(test1);
        //返回true
        System.out.println(matcher.matches());
        matcher = pattern.matcher(test2);
        //返回false
        System.out.println(matcher.matches());

        //lookingAt从字符串最开头开始匹配满足的子串
        matcher = pattern.matcher(test2);
        //返回true
        System.out.println(matcher.lookingAt());
        matcher = pattern.matcher(test3);
        //返回false
        System.out.println(matcher.lookingAt());


        //find可以对任意位置字符串匹配,其中start为起始查找索引值
        matcher = pattern.matcher(test1);
        //返回true
        System.out.println(matcher.find());
        matcher = pattern.matcher(test2);
        //返回true
        System.out.println(matcher.find());
        matcher = pattern.matcher(test3);
        //返回true
        System.out.println(matcher.find(2));
        matcher = pattern.matcher(test3);
        //返回false
        System.out.println(matcher.find(5));

【正确示例】

// 把Pattern 提到方法的外面,使其触发预编译
private static final Pattern pattern = Pattern.compile(regexRule);

private void function(...) {
Matcher m = pattern.matcher(content);

if (m.matches()) {
...

   }
}

总结

  • Pattern 表达式要提前定义,不要再需要的地方临时定义
  • Pattern 表达式要定义为 static final 静态变量,以避免执行多次预编译
    –对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)
    –对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)
  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值