正则表达式
一、基本语法
- 简单的转义符
| \n | 换行 |
| \t | Tab |
| \\ | 代表\ |
| \^, \$, \., \+ 等等 | 代表\后面的字符本身,^ $, 因为这些字符本身有其他含义,所以要在前面加转义符 |
- 标准字符
| \d | 0-9中任意一个数字 |
| \w | 任意一个字母或数字或下划线 |
| \s | 任意一个空格,制表符,换行符 |
| . | 小数点可以匹配任一字符,除了换行符。想要包括换行符,可以用[\s\S], \S是匹配除了空白符的其他所有字符 |
- 注意区分大小写,大写表示相反的意思。 例如 \s 和 \S
- 自定义字符集合,用[]表示,例如上面的[\s\S],表示的就是匹配括号内的内容。
| [ab5@] | 匹配"a"或"b"或“5”或"@" |
| [^abc] | 表示取相反,比如[^abc],表示匹配除abc以外的其他字母 |
| [f-k] | 匹配"f" - "k" 之间的任意一个字母 |
| [^A-F0-3] | 匹配"A"~"F", "0"~"3"之外的任意一个字符 |
- 注意:特殊字符在[ ] 里面失去其本身意义,比如 + - .这些符号。
- 量词 (Quantifier)
| {n} | 表达式重复n次,ex: \d{6}, 匹配任意6个数字 |
| {m, n} | 表达式至少重复m次,最多重复n次 |
| {m, } | 表达式最少重复m次 |
| ? | 匹配表达式0次或者1次,相当于{0, 1} |
| + | 表达式至少出现1次,相当于{1, } |
| * | 表达式不出现或出现任意次,相当于(0,} |
- 非贪婪模式,匹配越少越好,在表达式后面加个?号,例如:\d{3, 6}? , 尽量往3次匹配
- 字符边界(匹配的不是字符而是位置 ,符合某种条件的位置)
| ^ | 于字符串开始的地方匹配 |
| $ | 于字符串结束的地方匹配 |
| \b | 匹配一个单词边界, 这个位置前面的字符和后面的字符不全是\w |
- 分支结构,捕获组/非捕获组,反向引用
分支结构: | 表示或
捕获组:()
非捕获组 (?:Expression) :匹配到括号里的内容,但引用不到了,不会存下来,可以节省内存
反向引用:\n
ex: 怎么匹配到gogo, toto, dodo. ([a-z]{2})/1,([a-z]{2})是一个捕获组,代表匹配到两个字符,这个就匹配到了go,后面的反向引用:\1 ,指的是重复前面捕获组里面的内容一次,所以可以匹配到gogo
- 预搜索(零宽断言)
| (?=exp) | 断言自身出现的位置的后面能匹配表达式exp |
| (?<=exp) | 断言自身出现的位置的前面能匹配表达式exp |
| (?!exp) | 断言此位置的后面不能匹配表达式exp |
| (?<!exp) | 断言此位置的前面不能匹配表达式exp |
ex: 匹配所有以ing结尾的单词(doing, eating, going)
[a-z] +(?=ing) *注意:这个式子的匹配结果是doing,后面的 " ing " 不会被选中,因为在原表达式里的ing,是一个语法表达式,不是直接匹配
二、正则表达式练习
1、 电话号码验证
- 电话号码由数字和 " - " 构成
- 电话号码为7到8位
- 如果电话号码中包含区号,区号为3位或者4位,首位是0
- 区号用 " - " 和其他部分隔开
- 移动电话号码为11位
- 11位移动电话号码的第一位和第二位为 "13", "15", "18
//先考虑匹配固话 xxx(x)-xxxxxxx
0\d{2,3}-\d{7,9} // 0 + 两到三位的数字 + - + 7到9位的数字
//手机号
1[35789]\d{9}
//用括号和 | 连接
(0\d{2,3}-\d{7,9})|(1[35789]\d{9})
2、电子邮箱验证
[\w\-]+@[a-zA-Z0-9]+(\.[A-Za-z]{2, 4}){1,2}
三、正则表达式在Java中的使用
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 正则表达式在java中的使用
*/
public class Demo1 {
public static void main(String[] args) {
//表达式对象
Pattern p1 = Pattern.compile("\\w+"); //java里面正则要多一个右斜杠,切记
Pattern p2 = Pattern.compile("([a-z]+)([0-9])+");//匹配a-z字母和0-9数字,注意这个表达式有两段
//创建Matcher对象
Matcher m = p2.matcher("aa22###sxz531###zcx312");
//matches方法,返回一个布尔值,这里会返回false,因为有符号 #
Boolean Rst1 = m.matches();
//find方法,group方法。find会一次一次找下一个能匹配的子序列,group可以返回每一个子序列
while (m.find()){
System.out.println(m.group());
System.out.println(m.group(1));
System.out.println(m.group(2));
}
//替换
String str1 = m.replaceAll("&");
System.out.println(str1);
//分割,正则可以切割复杂的边界,而不仅仅依赖一个分割符(例如逗号)
String strAAA = "a3234b31231c321";
String[] strBBB = strAAA.split("\\d+"); //那数字分割。输出[a, b, c]
System.out.println(Arrays.toString(strBBB));
}
}
四、正则手写网络爬虫
/**
* 正则表达式,手写网络爬虫
*/
public class Demo1 {
//创建获得网页源码内容的方法
public static String getURLContent(String urlStr, String charSet){
StringBuilder sb = new StringBuilder();
try {
URL url = new URL(urlStr);
BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(), Charset.forName(charSet)));
String temp ="";
while ((temp=br.readLine())!=null){
sb.append(temp);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
public static List<String> getHyperlink(String desStr, String regexStr){
//利用正则表达式,寻找网页中的超链接
Pattern p = Pattern.compile(regexStr);
Matcher m = p.matcher(desStr);
List<String> result = new ArrayList<String>();
while (m.find()){
result.add(m.group(1));
}
return result;
}
public static void main(String[] args) {
String desStr = getURLContent("http://www.163.com", "gbk");
//Pattern p = Pattern.compile("<a[\\s\\S]+?</a>"); //在java中,\s要变\\s //取到超链接的整个内容
List<String> result = getHyperlink(desStr,"href=\"([\\w\\s./:]+?)\""); //只取超链接的有效地址
for (String temp : result){
System.out.println(temp);
}
}
}
浙公网安备 33010602011771号