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

前言

之前一直想要做一个自己的爬虫,然后从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]

边界匹配符

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

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

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

量词

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

贪婪型

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

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

勉强型

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

占有型

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

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

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

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("<tr>data</tr>");
    while(matcher.find()){
        System.out.println(matcher.group());
        //先后输出<tr> </tr>
    }

替换

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


jquery.validate使用攻略(表单校验) 目录 jquery.validate使用攻略1 第一章&#160;jquery.validate使用攻略1 第二章&#160;jQuery.validate.js API7 Custom selectors7 Utilities8 Validato
/\s+/g和/\s/g的区别 正则表达式/\s+/g和/\s/g,目的均是找出目标字符串中的所有空白字符,但两者到底有什么区别呢? 我们先来看下面一个例子: let name = &#39;ye wen jun&#39;;let ans = name.replace(/\s/g, &#39;&#3
自整理几个jquery.Validate验证正则: 1. 只能输入数字和字母 /^[0-9a-zA-Z]*$/g jQuery.validator.addMethod(&quot;letters&quot;, function (value, element) { return this.optio
this.optional(element)的用法 this.optional(element)是jquery.validator.js表单验证框架中的一个函数,用于表单控件的值不为空时才触发验证。 简单来说,就是当表单控件值为空的时候不会进行表单校验,此函数会返回true,表示校验通过,当表单控件
jQuery.validate 表单动态验证 实际上jQuery.validate提供了动态校验的方法。而动态拼JSON串的方式是不支持动态校验的。牺牲jQuery.validate的性能优化可以实现(jQuery.validate的性能优化见图1.2 jQuery.validate源码 )。 也可
自定义验证之这能输入数字(包括小数 负数 ) &lt;script type=&quot;text/javascript&quot;&gt; function onlyNumber(obj){ //得到第一个字符是否为负号 var t = obj.value.charAt(0); //先把非数字的都
// 引入了外部的验证规则 import { validateAccountNumber } from &quot;@/utils/validate&quot;; validator.js /*是否合法IP地址*/ export function validateIP(rule, value,cal
VUE开发--表单验证(六十三) 一、常用验证方式 vue 中表单字段验证的写法和方式有多种,常用的验证方式有3种: data 中验证 表单内容: &lt;!-- 表单 --&gt; &lt;el-form ref=&quot;rulesForm&quot; :rules=&quot;formRul
正则表达式 座机的: 例子: 座机有效写法: 0316-8418331 (010)-67433539 (010)67433539 010-67433539 (0316)-8418331 (0316)8418331 正则表达式写法 0\d{2,3}-\d{7,8}|\(?0\d{2,3}[)-]?\d
var reg = /^0\.[1-9]{0,2}$/;var linka = 0.1;console.log (reg.test (linka)); 0到1两位小数正则 ^(0\.(0[1-9]|[1-9]{1,2}|[1-9]0)$)|^1$ 不含0、0.0、0.00 // 验证是否是[1-10
input最大长度限制问题 &lt;input type=&quot;text&quot; maxlength=&quot;5&quot; /&gt; //可以 &lt;input type=&quot;number&quot; maxlength=&quot;5&quot; /&gt; //没有效
js输入验证是否为空、是否为null、是否都是空格 目录 1.截头去尾 trim 2.截头去尾 会去掉开始和结束的空格,类似于trim 3.会去掉所有的空格,包括开始,结束,中间 1.截头去尾 trim str=str.trim(); // 强烈推荐 最常用、最实用 or $.trim(str);
正则表达式语法大全 字符串.match(正则):返回符合的字符串,若不满足返回null 字符串.search(正则):返回搜索到的位置,若非一个字符,则返回第一个字母的下标,若不匹配则返回-1 字符串.replace(正则,新的字符串):找到符合正则的内容并替换 正则.test(字符串):在字符串中
正整数正则表达式正数的正则表达式(包括0,小数保留两位): ^((0{1}.\d{1,2})|([1-9]\d.{1}\d{1,2})|([1-9]+\d)|0)$正数的正则表达式(不包括0,小数保留两位): ^((0{1}.\d{1,2})|([1-9]\d.{1}\d{1,2})|([1-9]+
JS 正则验证 test() /*用途:检查输入手机号码是否正确输入:s:字符串返回:如果通过验证返回true,否则返回false /function checkMobile(s){var regu =/[1][3][0-9]{9}$/;var re = new RegExp(regu);if (r
请输入保留两位小数的销售价的正则: /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/ 1.只能输入英文 &lt;input type=&quot;text&quot; onkeyup=&quot;value
判断价格的正则表达式 价格的正则表达式 /(^[1-9]\d*(\.\d{1,2})?$)|(^0(\.\d{1,2})?$)/; 1 解析:价格符合两种格式 ^ [1-9]\d*(.\d{1,2})?$ : 1-9 开头,后跟是 0-9,可以跟小数点,但小数点后要带上 1-2 位小数,类似 2,2
文章浏览阅读106次。这篇文章主要介绍了最实用的正则表达式整理,比如校验邮箱的正则,号码相关,数字相关等等,本文给大家列举的比较多,需要的朋友可以参考下。_/^(?:[1-9]d*)$/ 手机号
文章浏览阅读1.2k次。4、匹配中的==、an==、== an9、i9 == "9i"和99p==请注意下面这部分的作用,它在匹配中间内容的时候排除了说明:当html字符串如下时,可以匹配到两处,表示匹配的字符串不包含and且不包含空白字符。说明:在上面的正则表达式中,_gvim正则表达式匹配不包含某个字符串
文章浏览阅读897次。【代码】正则表达式匹配a标签的href。_auto.js 正则匹配herf