资讯专栏INFORMATION COLUMN

正则表达式 深入浅出2--从java API开始

andycall / 648人阅读

摘要:正则表达式等待匹配的字符这里可以输入任何继承了的类返回一个值说明是否匹配这里需要注意的是,和均不允许通过构造器新建一个对象。

前言

之前一直想要做一个自己的爬虫,然后从nba数据相关的网上【虎扑,腾讯,官网等,要视网站是否支持】爬点数据写数据分析和图形化展示。虽然年轻的时候就实现过这个功能,但是当时直接借用了一个网上现成的jar包,然后在那个基础上写了一个非常简陋的正则表达式来提取数据。这次打算自己用JAVA API写一个爬虫,里面除了能读取HTML或是JSON或是XML,还要能够相应的支持多线程【这个功能将最后完成】。
今天这篇博客重点讲解java中和正则表达式相关的API为后序程序的实现做一个铺垫。后序的实现将在未来的博客3或4或5中展示,也会提供github源码来供大家参考和指教。所以也欢迎大家关注我,以便获得后序的更新。

进阶的正则表达式

关于正则表达式的基本知识请参考我的博客正则表达式 深入浅出1--你的符号我做主【持续更新中
在这里,我需要再补充一些博客1中没有提及但是必须了解的知识。(完整的正则表达式构造子列表请参考JAVA的API,在文章最后有给出传送门)

其它符号

在博客1中,我将最常用的一些符号整理出来,这里再说一些还需要了解的符号。

字符

xhh 十六进制值为0xhh的字符
uhhhh 十六进制表示为oxhhhh的Unicode字符

字符类

[abc[def]] 相当于合并操作 等价于[abcdef]
[a-z&&[hij]] 相当于交集操作,等价于[hij]
[a-z&&[^b-d]] 相当于减操作 等价于[ae-z]

边界匹配符

 词的边界,词的边界是指w和W之间的位置,它是一个定位符,并不代表任何具体的字符
B 非词的边界,也就是是w和w 以及W和W之间的位置

这里新添的两个定界符有点难理解。我们已知w是指词字符[a-zA-Z0-9],而W是指[^a-zA-Z0-9]。这里举个例子来说明bB都匹配了什么。
假设我们待匹配的字符串为"hello world! "
如果调用方法String[] result = s.split("");
那么我们会发现输出为["hello", "world", " ", "! rn"],也就是说我们可以将字符串看成是"_hello_ _world_! "其中_代表单词分界处。
那么如果_代表非单词分界处,那么上述句子可以表示成"h_e_l_l_o w_o_r_l_d!_ _ "

那么,在大多数情况下,我们都会通过词的边界符来实现获取而不是进行判断。

量词

量词描述了一个模式吸收输入文本的方式。量词总共分为三种,贪婪型、勉强型和占有型。下面分别介绍这三种量词以便更好的构建正则表达式。

贪婪型

贪婪型模式下的正则表达式会发现尽可能多的匹配。也就是说,即便当前情况已经满足了匹配,贪婪模式还是会继续测试下一个字符直至匹配失败为止。一旦匹配失败,就开始回退直至找到合适的匹配。

在默认情况下的一般正则表达式都是贪婪型的。

勉强型

在希望勉强匹配的正则表达式后面加?号即可进行勉强匹配。勉强匹配是指这个量词满足模式所需要的最小字符数就立刻停止。

占有型

目前,这种类型的量词只在JAVA中才可以用。占有型不同于前面两者,它不会进行回溯。我们知道一个正则表达式对应的字符串可能有多种。在贪婪型中,如果下一个匹配失败,则放出已占有字符回溯到上一个满足的情形继续判断。而勉强型则是多占有一个字符继续判断。占有型则不保存这些中间结果。一旦占有则不会释放。

下面举一个例子来说明这些情况:

输入的字符串:info
贪婪模式正则表达式:<.*>
返回输出:info
勉强模式正则表达式:<.*?>
返回输出:
占有模式正则表达式:<.*+>
返回输出:info

Pattern和Matcher API

在Java中,和正则表达式最息息相关的两个类就是PatternMatcher了。基本上所有正则表达式的底层实现都是通过Pattern和Matcher来实现的。比如说,我们非常了解的String中的matches方法,实际上也是通过Pattern和Matcher的配合来实现的。
在这篇博客中,我将介绍重点的API,详细的信息请各位自行参考JAVA DOC。

创建正则表达式并判断字符流是否符合。

    Pattern pattern = Pattern.compile("正则表达式");
    Matcher matcher = pattern.matcher("等待匹配的字符");//这里可以输入任何继承了CharSequence的类
    matcher.matches();//返回一个boolean值说明是否匹配

这里需要注意的是,Pattern和Matcher均不允许通过构造器新建一个对象。不仅如此,Pattern类是相对而言线程安全的,而Matcher类不是如此。

Pattern类

构造器

    static Pattern compile(String regex)
    static Pattern compile(String regex, int flag);

第二个构造pattern的方法中多了一个flag参数,这个参数允许我们定义pattern的模式,这里讲几个比较重要的模式:

Pattern.CASE_INSENSITIVE: 等价于正则表达式中的?i,是的匹配可以大小写不敏感
Pattern.COMMENTS : 等价于正则表达式中的?x,会忽略空格符和以#开头到行末的注释
Pattern.MULTILINE : 等价于?m,使得^和&符号可以匹配一行的始末,而不仅仅是整个字符串的始末

如果希望有多个Pattern,可以输入Pattern.compile("正则表达式", Pattern1 | Pattern2 | Pattern3)

分割
Pattern自己也定义了split方法。它会根据之前compile的正则表达式进行分割并返回String[],limit值是指分割出的String[]的size不会超过这个limit值。

String[] split(CharSequences c, int limit)
String[] split(CharSequences c)

分组
在这里还需要在讲解一个分组的概念以便为后面做铺垫。正则表达式的分组是指将一对括号中的表达式划为一个分组。因此形如A(B(CD)(E))的正则表达式一共有四个分组{A(B(CD)(E)),B(CD)(E),(CD),(E)},其中第0个分组默认为完整的正则表达式。

Matcher类

查找

     int groupCount() //返回除了第0组的总分组数
     boolean find() //从当前下标开始匹配,如果存在满足正则表达式的值,则返回true
     boolean find(int i)//从下标i开始匹配,如果存在满足正则表达式的值,返回true
     String group() //返回前一次匹配的第0个分组的内容
     String group(int i)//返回前一次匹配的第i个分组的内容
     int start() //返回上一次匹配成功的内容的起始下标
     int end() //返回上一次匹配成功的内容的终止下标+1

举个栗子

    Pattern p = Pattern.compile("<.*?>");
    Matcher matcher = p.matcher("data");
    while(matcher.find()){
        System.out.println(matcher.group());
        //先后输出 
    }

替换

    void replaceFirst(String replacement);
    void replaceAll(String replacement);
    void appendReplacement(StringBuffer s, String replacement);
    void appendTail(StringBuffer s);

这里讲一下appendReplacement和appendTail方法。appendReplacement允许开发者在替换的过程中针对将被替换的内容进行一些动态的操作。这个方法将逐步推进的向前替换,并将替换的结果添加到输入的s中。除此以外,对于没有被扫描到的部分,可以通过appendTail方法添加到输入的s中。

例子:

    Pattern p = Pattern.compile("hello", Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher("hello world one hello world 2");
    StringBuffer s = new StringBuffer();
    while(m.find()){
        m.appendReplacement(s, m.group().toUpperCase());
        System.out.println(s);
    }
    m.appendTail(s);
    System.out.println(s);

输出为:

小结

其实正则表达式的适用范围非常广,除了和CharSequence配合使用之外,还可以和JAVA I/O如Scanner类,InputReader类等联合使用。核心还是在于Pattern类和Matcher类的组合使用。

References

JAVA API

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70212.html

相关文章

  • Java进阶之路

    摘要:探索专为而设计的将探讨进行了何种改进,以及这些改进背后的原因。关于最友好的文章进阶前言之前就写过一篇关于最友好的文章反响很不错,由于那篇文章的定位就是简单友好,因此尽可能的摒弃复杂的概念,只抓住关键的东西来讲,以保证大家都能看懂。 周月切换日历 一个可以进行周月切换的日历,左右滑动的切换月份,上下滑动可以进行周,月不同的视图切换,可以进行事件的标记,以及节假日的显示,功能丰富 Andr...

    sushi 评论0 收藏0
  • Java深入 - Java正则表达 Pattern和Matcher

    摘要:它包括两个类和一个是一个正则表达式经编译后的表现模式。这个标志能让表达式忽略大小写进行匹配。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。返回当前查找而获得的与指定的组匹配的子串内容 Pattern和MatcherJava.util.regex 是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包。它包括两个类:Pattern和MatcherPattern: 一个Patt...

    baiy 评论0 收藏0
  • java正则表式的使用

    摘要:直接使用正则表达式对输入的字符串进行匹配,匹配成功则返回使用正则表示式,进行字符串分割进行匹配操作,如果匹配成功,这三个方法都会返回其中,是在源字符串中找出和正则表达式匹配的字符串。 概念 正则表达式 在阅读本文前,你应该已经了解了正则表达式的基本概念以及如何书写正则表达式。如果对正则表达式不是太了解,或者想更深入地了解正则表示式,请点击这里。 捕获组 捕获组能够让我们方便地从正则表达...

    zoomdong 评论0 收藏0
  • Java开发

    摘要:大多数待遇丰厚的开发职位都要求开发者精通多线程技术并且有丰富的程序开发调试优化经验,所以线程相关的问题在面试中经常会被提到。将对象编码为字节流称之为序列化,反之将字节流重建成对象称之为反序列化。 JVM 内存溢出实例 - 实战 JVM(二) 介绍 JVM 内存溢出产生情况分析 Java - 注解详解 详细介绍 Java 注解的使用,有利于学习编译时注解 Java 程序员快速上手 Kot...

    LuDongWei 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<