以前一直想要作一个本身的爬虫,而后从nba数据相关的网上【虎扑,腾讯,官网等,要视网站是否支持】爬点数据写数据分析和图形化展现。虽然年轻的时候就实现过这个功能,可是当时直接借用了一个网上现成的jar包,而后在那个基础上写了一个很是简陋的正则表达式来提取数据。此次打算本身用JAVA API写一个爬虫,里面除了能读取HTML或是JSON或是XML,还要可以相应的支持多线程【这个功能将最后完成】。
今天这篇博客重点讲解java中和正则表达式相关的API为后序程序的实现作一个铺垫。后序的实现将在将来的博客3或4或5中展现,也会提供github源码来供你们参考和指教。因此也欢迎你们关注我,以便得到后序的更新。java
关于正则表达式的基本知识请参考个人博客正则表达式 深刻浅出1--你的符号我作主【持续更新中
在这里,我须要再补充一些博客1中没有说起可是必须了解的知识。(完整的正则表达式构造子列表请参考JAVA的API,在文章最后有给出传送门)git
在博客1中,我将最经常使用的一些符号整理出来,这里再说一些还须要了解的符号。github
字符正则表达式
\xhh
十六进制值为0xhh的字符\uhhhh
十六进制表示为oxhhhh的Unicode字符segmentfault
字符类api
[abc[def]]
至关于合并操做 等价于[abcdef][a-z&&[hij]]
至关于交集操做,等价于[hij][a-z&&[^b-d]]
至关于减操做 等价于[ae-z]安全
边界匹配符多线程
\b
词的边界,词的边界是指\w和\W之间的位置
,它是一个定位符,并不表明任何具体的字符\B
非词的边界,也就是是\w和\w 以及\W和\W
之间的位置oracle
这里新添的两个定界符有点难理解。咱们已知\w是指词字符[a-zA-Z0-9]
,而\W是指[^a-zA-Z0-9]
。这里举个例子来讲明b和B都匹配了什么。
假设咱们待匹配的字符串为"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"
app
那么,在大多数状况下,咱们都会经过词的边界符来实现获取而不是进行判断。
量词描述了一个模式吸取输入文本的方式。量词总共分为三种,贪婪型、勉强型和占有型。下面分别介绍这三种量词以便更好的构建正则表达式。
贪婪型
贪婪型模式下的正则表达式会发现尽量多的匹配。也就是说,即使当前状况已经知足了匹配,贪婪模式仍是会继续测试下一个字符直至匹配失败为止。一旦匹配失败,就开始回退直至找到合适的匹配。
在默认状况下的通常正则表达式都是贪婪型的。
勉强型
在但愿勉强匹配的正则表达式后面加?号便可进行勉强匹配。勉强匹配是指这个量词知足模式所须要的最小字符数就马上中止。
占有型
目前,这种类型的量词只在JAVA中才能够用。占有型不一样于前面二者,它不会进行回溯。咱们知道一个正则表达式对应的字符串可能有多种。在贪婪型中,若是下一个匹配失败,则放出已占有字符回溯到上一个知足的情形继续判断。而勉强型则是多占有一个字符继续判断。占有型则不保存这些中间结果。一旦占有则不会释放。
下面举一个例子来讲明这些状况:
输入的字符串:<tr>info</tr>
贪婪模式正则表达式:<.*>
返回输出:<tr>info</tr>
勉强模式正则表达式:<.*?>
返回输出:<tr>
占有模式正则表达式:<.*+>
返回输出:<tr>info</tr>
在Java中,和正则表达式最息息相关的两个类就是Pattern
和Matcher
了。基本上全部正则表达式的底层实现都是经过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类不是如此。
构造器
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个分组默认为完整的正则表达式。
查找
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类的组合使用。