一、正则表达式
非打印字符
\n | 匹配一个换行符 |
\r | 匹配一个回车符 |
\f | 匹配一个换页符 |
\t | 匹配一个制表符 |
\s | 匹配任何空白字符包括空格、制表符、换页符等 |
\v | 匹配一个垂直制表符 |
\S | 匹配任何非空白字符 |
\cx | 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 |
标准字符集合
能够与多种字符进行匹配的表达式,注意区分大小写,大写表示相反的意思
\d | 任意一个数字,0-9中的任意一个 |
\w | 任意一个字母或者数字或者下划线,也就是A-Z,a-z,0-9,_,中的任意一个 |
\s | 包括空格、制表符、换行符等空白字符的其中任意一个 |
小数点可以匹配任意一个字符(除了换行符)
如果要匹配包括"\n" 在内的所有字符 一般用[\s\S]
自定义字符集合
[]方括号匹配方式,能够匹配方括号中任意一个字符
例如: [ab5@] 匹配"a"或者"b" 或者"5"或者"@"
[^abc] 匹配"a""b""c"之外的任意一个字符(因为是^代表异或)
[f-k]匹配"f-k"之间的任意一个字母
[^A-F0-3]匹配"A"-"F" "0"-"3"之外的任意一个字符
正则表达式的特殊符号,被包括到中括号中,则失去了特殊意义,除了^,-,之外
标准字符集合,除了小数点外,如果被包括于中括号,自定义字符集合将包含该集合,比如:[\d.\-+]将匹配:数字、小数点、+、-
量词
修饰匹配次数的特殊符号
{n} 表达式重复n次 例如\d{3} 会匹配345,332,367,456等三位数字
{m,n} 表达式至少重复m次,最多重复n次 \d{3,6} 会匹配3345,345,567,56667等三位--六位数字
{m,} 表达式至少重复m次 \d{3,} 会匹配344,577,666666,666666666666等至少3位数字
? 匹配表达式0次或者1次相当于{0,1}
+ 表达式至少出现1次,相当于{1,}
* 表达式不出现或者出现任意次,相当于{0,}
匹配次数中的贪婪模式(匹配字符越多越好,默认!) \d{3,6} 有个字符串1234567 会匹配123456
匹配次数中的非贪婪模式(匹配字符越少越好,修饰匹配次数的特殊符号后再加上一个"?"号)
\d{3,6}? 有个字符创1234567 会匹配123 456 两个结果
位置匹配
字符边界
(本组标记匹配的不是字符而是位置,符合某种条件的位置)
^ 与字符串开始的地方匹配 例如: asdadajdkasdh ^a 会匹配字符串asdadajdkasdh中的a
$ 与字符串结束的地方匹配 例如: abcdefgggcdd 那么b$会匹配字符串abcdefgggcddb中b
因为b的右侧是字符串结尾的地方
\b 匹配一个单词的边界 (\b匹配这样一个位置:前面的字符和后面的字符不全是\w )
例如:yangdidi2222 2222yangdidi 22222yangdidi22222 yangdidi
那么i\b会匹配 2222yangdidi yangdidi
那么\by 会匹配 yangdidi2222 yangdidi
\b的大致意思就是如果你前面和后面都是\w(字母或者数字或者下划线)那么我就不匹配你
模式
- Ignorecase 忽略大小写模式
匹配时忽略大小写
默认情况下,正则表达式是要区分大小写的。
- SingleLine 单行模式
整个文本看做一个字符串,只有一个开头,一个结尾
使小数点"."可以匹配包含换行符(\n)在内的任意字符
例如:aaaaq1111111111111
ffffffadsadasdsa
ads111111111111
那么^a只会匹配第一个a
- Multiline 多行模式
每行都是一个字符串 都有开头和结尾
在指定了multiline之后,如果需要仅匹配字符串开始和结束的位置,可以使用\A和\Z
例如
aaaaq1111111111111
ffffffadsadasdsa
ads111111111111
^a会匹配第一行的a和第三行的a
如果使用了\Aa只会匹配第一行的a,同理1\Z 只会匹配最后一行的1
选择符和分组
表达式 作用
| 分支结构 左右两边表达式之间"或"的关系,匹配左边或者右边
() 捕获组 (1)在被修饰匹配的次数的时候,括号中的表达式可以作为整体被修饰
(2) 取匹配结果的时候,括号中的表达式匹配到的内容可以被单独得到
(3) 每一对括号会分配一个编号,使用()的捕获根据左括号的顺序从1开始自动编号,捕获元素编号为零的第一 个捕获是整个正则表达式模式匹配的文本
(?:Expresssion) 一些表达式中,不得不使用(),但是又不需要保存()中子表达式匹配的内容,这时可以用非捕获组来抵消使用()带来的副作用
反向引用:
每一对()会分配一个编号,使用()的捕获根据左括号的顺序从1开始自动编号通过反向引用,可以对分组已捕获的字符串进行引用
例如:
([a-z]{2})\1
可以匹配到gogo toto dodo 原因是([a-z]{2})表示匹配两个字符的结果那么\1表示前面的括号中的匹配结果
那么([a-z]{2})\1就是两个重复的结果
预搜索
只进行子表达式的匹配,匹配内容不计入最终匹配结果,是零宽度
这个位置应该符合某个条件,判断当前位置的前后字符,是否符合指定的条件,但不匹配前后的字符
是对位置的匹配
正则表达式匹配过程中,如果子表达式匹配到的是字符内容,而非位置,并被保存到最终的匹配结果中,那么就认为这个子表达式是占有字符的,如果子表达式匹配的仅仅是位置,或者匹配的内容并不保存到最终的匹配的结果中,那么就认为这个子表达式是零宽度的。占有字符还是零宽度,针对匹配的内容是否保存到最终的匹配结果中而言的
(?=exp) 断言自身出现的位置的后面能匹配表达式exp
(?<=exp) 断言自身出现的位置的前面匹配表达式exp
(?!exp) 断言此位置的后面不能匹配表达式exp
(?<!exp) 断言此位置的前面不能匹配表达式exp
例如: going eating
([a-z]+)(?=ing) 那么匹配的结果为 go eat
----当然正则表达式还有很多知识点
二、正则表达式在java中的使用
主要涉及两个类:Pattern和Matcher类
Pattern
代表了正则表达式的编译形式
Pattern.compile(String regex) 返回了一个Pattern 对象
public static Pattern compile(String regex, int flags) {
return new Pattern(regex, flags);
}
使用:
Pattern pattern=Pattern.compile("\\w+");
matches(String regex, CharSequence input) 编译给定正则表达式并尝试将给定输入与其匹配。
public static boolean matches(String regex, CharSequence input) {
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(input);
return m.matches();
}
public Matcher matcher(CharSequence input) 输入目标字符串然后进行匹配结果
public Matcher matcher(CharSequence input) {
if (!compiled) {
synchronized(this) {
if (!compiled)
compile();
}
}
Matcher m = new Matcher(this, input);
return m;
}
String pattern() 返回正则表达式的字符串形式
public String pattern() {
return pattern;
}
例如:
Pattern pattern=Pattern.compile("\\w+");
System.out.println(pattern.pattern());
\w+
String[] split(CharSequence input) //Pattern有一个split(CharSequenceinput)方法,用于分隔字符串,并返回一个String[]。此外String[] split(CharSequence input, int limit)功能和String[]split(CharSequence input)相同,增加参数limit目的在于要指定分割的段数
public String[] split(CharSequence input, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<>();
Matcher m = matcher(input);
// Add segments before each match found
while(m.find()) {
if (!matchLimited || matchList.size() < limit - 1) {
if (index == 0 && index == m.start() && m.start() == m.end()) {
// no empty leading substring included for zero-width match
// at the beginning of the input char sequence.
continue;
}
String match = input.subSequence(index, m.start()).toString();
matchList.add(match);
index = m.end();
} else if (matchList.size() == limit - 1) { // last one
String match = input.subSequence(index,
input.length()).toString();
matchList.add(match);
index = m.end();
}
}
// If no match was found, return this
if (index == 0)
return new String[] {input.toString()};
// Add remaining segment
if (!matchLimited || matchList.size() < limit)
matchList.add(input.subSequence(index, input.length()).toString());
// Construct result
int resultSize = matchList.size();
if (limit == 0)
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
resultSize--;
String[] result = new String[resultSize];
return matchList.subList(0, resultSize).toArray(result);
}
写的比较好的链接
Matcher类
boolean matches()最常用方法:尝试对整个目标字符展开匹配检测,也就是只有整个目标字符串完全匹配时才返回真值。
boolean lookingAt()对前面的字符串进行匹配,只有匹配到的字符串在最前面才会返回true。
boolean find():对字符串进行匹配,匹配到的字符串可以在任何位置
int start() : 返回当前匹配到的字符串在原目标字符串中的第一个字符位置
int end() : 返回当前匹配到的字符串的最后一个字符在原目标字符串中的位置索引
Matcher region(int start, int end):设置此匹配器的区域限制
String replaceAll(Stringreplacement):将目标字符串里与既有模式相匹配的子串全部替换为指定的字符串。
String replaceFirst(Stringreplacement):将目标字符串里第一个与既有模式相匹配的子串替换为指定的字符串
Matcher appendReplacement(StringBuffersb, String replacement)
StringBufferappendTail(StringBuffer sb)
appendReplacement允许直接将匹配的字符串保存在另一个StringBuffer中并且是渐进式匹配,并不是只匹配一次或匹配全部,而
appendTail则是将未匹配到的余下的字符串添加到StringBuffer中
三、应用
简单使用:find()
package regx;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
Pattern pattern=Pattern.compile("\\w+");
System.out.println(pattern.pattern());
//注意在java中正则表达式\变成\\
Matcher aMatcher=pattern.matcher("aaaaaqq&&weqg12313");
System.out.println( aMatcher.find());
System.out.println(aMatcher.group());
System.out.println( aMatcher.find());
System.out.println(aMatcher.group());
}
}
实现结果:
\w+
true
aaaaaqq
true
weqg12313
group() group(int index)
package regx;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
Pattern pattern=Pattern.compile("([a-z]+)(\\d+)");
System.out.println(pattern.pattern());
//注意在java中正则表达式\变成\\
Matcher aMatcher=pattern.matcher("aaa1211&&weqg12313");
while (aMatcher.find())
{
System.out.println("匹配到的子字符串"+aMatcher.group());
System.out.println("匹配到的子字符串中的第一个部分"+aMatcher.group(1));
System.out.println("匹配到的子字符串中的第二个部分"+aMatcher.group(2));
}
}
}
实现结果:
([a-z]+)(\d+)
匹配到的子字符串aaa1211
匹配到的子字符串中的第一个部分aaa
匹配到的子字符串中的第二个部分1211
匹配到的子字符串weqg12313
匹配到的子字符串中的第一个部分weqg
匹配到的子字符串中的第二个部分12313
//group()表示当前匹配到的子字符串, group(1)表示子字符串中的符合正则表达式中第一部分中的结果,同理group(2)表示子字符串中的符合正则表达式中第二部分中的结果
replaceAll(String replacement)//将匹配到的子字符串替换成目标字符串
package regx;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
Pattern pattern=Pattern.compile("([a-z]+)(\\d+)");
System.out.println(pattern.pattern());
//注意在java中正则表达式\变成\\
Matcher aMatcher=pattern.matcher("aaa1211&&weqg12313");
//将匹配到的子字符串替换成目标字符串
String cString=aMatcher.replaceAll("love");
System.out.println(cString);
}
}
实现结果:
([a-z]+)(\d+)
love&&love
四、简单实现网络爬虫程序
package regx;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Search {
public static void main(String[] args) throws IOException {
URL url=new URL("http://www.ecjtu.jx.cn/");
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(url.openStream(),"utf-8"));
String temp="";
StringBuffer stringBuffer=new StringBuffer();
while((temp=bufferedReader.readLine())!=null)
{
stringBuffer.append(temp);
stringBuffer.append("\n");
}
Pattern pattern2=Pattern.compile("href=\"([\\w\\s./:]+?)\"");
Matcher matcher=pattern2.matcher(stringBuffer);
while(matcher.find())
{
System.out.println(matcher.group());
}
}
}
实现结果:
href="http://jwc1.ecjtu.edu.cn"
href="http://yjsy.ecjtu.edu.cn"
href="http://jxjy.ecjtu.edu.cn"
href="http://jwc1.ecjtu.edu.cn"
href="http://jgxy.ecjtu.edu.cn/gsglss/list.htm"
href="http://mpacc.ecjtu.edu.cn"
href="http://jgxy.ecjtu.edu.cn/030701/list.htm "
href="http://ecjtu.fy.chaoxing.com"
href="http://mpa.ecjtu.edu.cn"
href="http://kyc.ecjtu.edu.cn/"
href="http://gdzx.ecjtu.edu.cn/"
href="http://journal.ecjtu.edu.cn/ch/index.aspx"
href="http://ometa.ecjtu.edu.cn/"
href="http://td.ecjtu.jx.cn/"
href="http://iei.ecjtu.edu.cn/"
href="http://jxaco.ecjtu.edu.cn/"
href="http://vriti.ecjtu.edu.cn"
href="http://chsr.ecjtu.edu.cn"
href="https://iam.ecjtu.edu.cn/"
href="http://kmh.ecjtu.edu.cn"
href="http://yywz.ecjtu.edu.cn"
href="http://huadong.ciptc.org.cn/public/index"
href="http://flswb.ecjtu.jx.cn/"
href="http://wsdx.ecjtu.edu.cn/"
href="/238/list.htm"
href="http://zxjf.ecjtu.edu.cn/"
href="http://lib.ecjtu.edu.cn/"
href="http://525.ecjtu.edu.cn/"
href="http://dag.ecjtu.edu.cn"
href="http://lib.ecjtu.edu.cn/2914/list.htm"
href="/245/list.htm"
href="http://zjc.ecjtu.edu.cn/recruit/index"
href="http://zjc.ecjtu.edu.cn"
href="http://yjsy.ecjtu.edu.cn/"
href="http://jxjy.ecjtu.edu.cn"
href="http://hjlx.ecjtu.edu.cn/"
href="/339/list.htm"
href="http://gjc.ecjtu.edu.cn/"
href="http://www.ecjtu.jx.cn"
href="http://xw.ecjtu.edu.cn"
href="http://news.ecjtu.edu.cn"
href="http://xw.ecjtu.edu.cn/1085/list.htm"
href="/186/list.htm"
href="/188/list.htm"
href="/189/list.htm"
href="/190/list.htm"
href="/191/list.htm"