第26次文章:正则表达式
- 2019 年 10 月 8 日
- 筆記
正则表达式专场,欢迎阅读哟!
一、正则表达式简介regular expression
1、为什么需要正则表达式
文本的复杂处理。
2、正则表达式的优势和用途
一种强大而灵活的文本处理工具。大部分编程语言、数据库、文本编辑器、开发环境都支持正则表达式
3、正则表达式定义
正如他的名字一样是描述了一个规则,通过这个规则可以匹配一类字符串。学习正则表达式很大程度上就是学习正则表达式的语法规则。
4、开发中使用正则表达式的流程
(1)分析所要匹配的数据,写出测试用的典型数据
(2)在工具软件中进行匹配测试
(3)在程序中调用通过测试的正则表达式
二、正则表达式语法
1、标准字符集合
(1)能够与‘多种字符’匹配的表达式
(2)注意区分大小写,大写是相反的意思

2、自定义字符集合
[]方括号匹配方式,能够匹配方括号中任意一个字符

(1)正则表达式的特殊符号,被包含到中括号中,则失去特殊意义,除了^,-之外。
(2)标准字符集合,除小数点外,如果被包含于中括号,自定义字符集合将包含该集合。比如:[d. -+]将匹配数字、小数点、+、-
3、字符边界
本组标记匹配的不是字符而是位置,符合某种条件的位置-零宽

b 匹配这样一个位置:前面的字符和后面的字符不全是w
4、匹配模式
(1)IGNORCASE忽略大小写模式
匹配时,忽略大小写。默认情况下,正则表达式是要区分大小写的。
(2)SINGLELINE单行模式
整个文本看做一个字符串,只有一个开头,一个结尾。使小数点“.”可以匹配包含换行符(n)在内的任意字符。
(3)MULTILINE多行模式
每行都是一个字符串,都有开头和结尾。在指定了MULTILINE之后,如果需要仅匹配字符串开始和结束为止,可以使用A和Z
5、选择符和分组

6、反向引用(nnn)
对一个正则表达式模式或部分模式两边添加圆括号,将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 n 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。通过反向引用,可以对分组已捕获的字符串进行引用。
7、预搜索(零宽断言)
(1)只进行子表达式的匹配,匹配内容不计入最终的匹配结果,是零宽度。
(2)这个位置应该符合某个条件。判断当前位置的前后字符,是否符合指定的条件,但不匹配前后的字符。是对位置的匹配。
(3)正则表达式匹配过程中,如果子表达式匹配到的是字符内容,而非位置,并被保存到最终的匹配结果中,那么就认为这个子表达式是占有字符的;如果子表达式匹配的仅仅是位置,或者匹配的内容并不保存到最终的匹配结果中,那么就认为这个子表达式是零宽的。占有字符还是零宽度,是针对匹配的内容是否保存到最终的匹配结果中而言的。

三、正则表达式在java中的应用
在java中如果需要使用正则表达式,可以按照既定的步骤进行实现。
1、具体步骤
(1)把正则表达式表示成java中的一个对象
(2)把正则表达式和目标字符串通过matcher对象关联起来
(3)利用matches方法进行查找
2、简单实现
(1)首先来简单测试一下正则表达式的基本用法
public class Demo01 { public static void main(String[] args) { //在这个字符串:shdakhskhfdkjs214654321,是否符合指定的正则表达式:w+ //表达式对象 Pattern p = Pattern.compile("\w+"); //创建Matcher对象 Matcher m = p.matcher("shdakhskhfd&&kjs214654321"); boolean yesorno = m.matches();//尝试将整个字符序列与该模式匹配 System.out.println(yesorno); System.out.println(m.find());//该方法扫描输入的序列,查找与该模式匹配的下一个子序列 System.out.println(m.group());//group()返回匹配到的字符串子序列 System.out.println(m.find()); System.out.println(m.group()); }}
结果图:

tips:
(1)我们按照上述的基本步骤进行建立对象,当我们获取到matcher对象之后,主要就是根据matcher对象的方法,对目标字符串进行相应的处理。
(2)我们主要使用了matches()、group()和find()函数,三个函数的主要用法都已经在注释中标出。
需要注意一点的是,在使用正则表达式的转义字符的时候,我们的正则语法是在字母前面加' ',但是在Java中,所有的' ',都需要变为' '。这一点需要各位小伙伴注意一下哈!
(2)测试分组处理
public class Demo02 { public static void main(String[] args) { //表达式对象 Pattern p = Pattern.compile("([a-z]+)([0-9]+)"); //创建Matcher对象 Matcher m = p.matcher("dsjdag4564**dsg4654**djs654"); while(m.find()) { System.out.println(m.group());//group(),group(0)匹配整个表达式的字符串 System.out.println(m.group(1)); System.out.println(m.group(2)); } }}
结果图:

tips:
(1)在这段代码中,比较好的解释了正则表达式中分组的概念,我们的正则表达式是匹配字符串和数字的混合模式,在正则表达式中,我们使用小括号将字符串和数字进行了一个小的分组。所以,当我们使用find函数的时候,首先会在整个目标字符串中寻找符合正则表达式的子字符串,然后在寻找到的子字符串中,会根据我们在正则表达式中的“(”,将每一个括号中匹配到的内容重新编号,这样我们可以使用Java中的group(int)进行调用每一个小括号中的正则表达内容。
(2)比如在我们这段代码中,我们的正则表达式由两个小括号共同完成,分别代表着字符串和数字。而字符串处于第一个小括号中,数字处于第二个小括号中,所以在while循环中,我们可以使用group(int)的方式输出每一个捕获组。
四、做一个网络爬虫
我们利用上面的正则表达式,结合我们前面学习到的网络编程知识,来编写一个网络爬虫的小程序,将一个网页中所包含的网址全部爬取出来。代码如下:
package com.peng.regex.test; import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.MalformedURLException;import java.net.URL;import java.nio.charset.Charset;import java.util.ArrayList;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern; /** * 网络爬虫取链接 * @author 赵晓鹏 * */public class WebSpiderTest { public static void main(String[] args) { String destStr = getURLContent("http://www.163.com","gbk"); String regStr = "href="([\w\s./:]+?)"";//正则表达式 List<String> list = getMatcherSubstrs(destStr,regStr);//取到的超链接的地址 for(String temp:list) { System.out.println(temp); } } /** * 从匹配到的字符串中筛选出子字符串 * @param destStr * @param regStr * @return */ public static List<String> getMatcherSubstrs(String destStr,String regStr){ List<String> list = new ArrayList<String>();//创建一个字符串容器,用于存储字符串数组 Pattern p = Pattern.compile(regStr);//匹配正则字符串 Matcher matcher = p.matcher(destStr);//将正则表达式与目标字符串进行匹配 while(matcher.find()) { list.add(matcher.group(1));//将正则表达式中的第一个分组存入容器中 } return list; } /** * 获得urlStr对应的网页的源码内容 * @param urlStr 传入需要爬取的网络地址 * @param charset 指定的编码集,避免在解码的时候出现乱码 * @return */ public static String getURLContent(String urlStr,String charset) { StringBuilder sb = new StringBuilder(); try { URL url = new URL(urlStr);//将网址传输进来 BufferedReader reader = new BufferedReader(new InputStreamReader (url.openStream(),Charset.forName(charset)));//为此网络连接打开一个输入流 String tempStr ; while((tempStr = reader.readLine())!=null) { sb.append(tempStr);//将目标网页的源码全部连接在一起,成为一个字符串 } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return sb.toString();//以字符串的形式返回 }}
结果图:

tips:
在这段网络爬虫的代码中,我们自己编写了一个获取网站源码的方法getURLContent(),以及一个匹配正则表达式的方法getMatcherSubstrs()。我们首先利用getURLContent()方法获取到了一个网站的源码。经过对源码的分析之后发现,源码中包含的各个网络地址链接的格式都是较为固定的,所有的网址的格式均为:href="字符串+空白符+.+/",所以我们在使用正则表达式的时候,将其中的href作为开头,然后将后面的网址信息用一个小括号包围起来作为一个捕获组,然后就可以在整个网站的源码中进行筛选,并取出每个捕获组,就可以获得我们的目标信息。