java正则表达式学习
可以参考:https://www.runoob.com/java/java-regular-expressions.html
1.简单认识正则:
public class Test { public static void main(String[] args) { //简单认识正则 p("abc".matches("...")); p("a8729a".replaceAll("\\d", "-")); } public static void p(Object o){ System.out.println(o); } }
一个.代表一个字母
true
a----a
2.简单认识Pattern和Matcher:
/** * 比下面一句话的好处: * 1.Pattern.compile将正则表达式先编译了,速度更快; * 2.Pattern 和Matcher有更多的方法,是String.matches所没有的; */ Pattern p = Pattern.compile("[a-z]{3}"); Matcher m = p.matcher("fgh"); p(m.matches()); p("fgh".matches("[a-z]{3}")); //相当于上面三句话
true
true
解释:
/**
* Pattern:模式,[a-z]{3}的这种模式。
* Matcher:匹配器;[a-z]{3}的这种模式去匹配"fgh"这个字符串;
* 匹配这个字符串的过程之中,要注意有可能产生多个结果,匹配的结果会保留在Matcher对象m里面。
* 这个结果是匹配还是不匹配呢?调用m.matches();
*/
3.初步认识. * + ?
/** * 初步认识 . * + * . 任意一个字符 * * 0个或多个 * + 1个或多个 * ? 0个或1个,可有可无。 */ p("a".matches(".")); //true p("aa".matches("aa")); //true p("aaaa".matches("a*")); //true p("aaaa".matches("a+")); //true p("".matches("a*")); //true p("aaaa".matches("a?")); //false p("".matches("a?")); //true p("a".matches("a?")); //true p("214523145234532".matches("\\d{3,100}")); //true p("192.168.0.aaa".matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")); //false p("192".matches("[0-2][0-9][0-9]")); //true
解释:
.是一个特殊的字符,用转义字符,所以写\. 可是\在正则表达式里面确实是\,但是在java里面比较特殊,用两个\\。
所以\\.代表.这个字符。
4.范围:
/** * 范围 * []里面匹配一个字符。中括号里面写的再长,也是匹配一个字符 */ p("a".matches("[abc]")); p("a".matches("[^abc]")); //取反,除了abc之外的内容 p("A".matches("[a-zA-Z]")); //大写字母或小写字母 p("A".matches("[a-z]|[A-Z]")); //这种写法和上面写法一样 p("A".matches("[a-z[A-Z]]")); //也是a-z或者A-Z的意思 p("R".matches("[A-Z&&[RFG]]")); //A-Z中的,并且是RFG之一的
true
false
true
true
true
true
[]中匹配字符横杠-,须转义: [\\-]
[]中匹配冒号:,直接匹配即可,[:]
[]中匹配问号?, 直接匹配即可,[?]
[]中匹配反斜杠,[\\\\]
4.1 或符号
“|”操作符的基本意义就是“或”运算
x|y 匹配 x 或 y。例如,'z|food' 匹配"z"或"food"。'(z|f)ood' 匹配"zood"或"food"。
t(a|e|i|o|oo)n 可以匹配“toon”,这里不能使用方扩号,因为方括号只允许匹配单个字符;这里必须使用圆括号“()”。圆括号还可以用来分组
4.2 圆括号
圆括号用法:
1.对字符或元字符进行分组,这样在圆括号内就可以对字符组合使用限定符
eg:匹配A+一个数字+A+一个数字:(A\d){2}
2.表示可选择性
a:从两个直接量中选择一个
eg: gr(a|e)y匹配gray和grey,该例子还可以使用gr[ae]y,字符类效率更高
b:从多个直接量中选择
eg. (Doctor|Dr\.?)匹配Doctor,Dr,Dr.三种情况
3.捕获圆括号:正则表达式中,与位于圆括号之间的模式匹配的内容都会被捕获
当模式中有嵌套的圆括号时,变量的编号会按照圆开括号出现的位置一次进行
eg. ([A-Za-z](\d{2}))((-)\d{2})匹配”A22-33”时,匹配情况如下:
Group 1: A22
Group 2: 22
Group 3: -33
Group 4: -
4.非捕获的圆括号:即圆括号的内容不作为捕获对象,当圆括号中的内容不是想捕获的对象时,采用非捕获圆括号可以提高匹配效率。语法为:
(?:the-non-captured-content)
eg. (\w(?:\d{2}))((?:-)\d{2})匹配” A22-33”情况如下:
Group 1: A22
Group 2: -33
注:\d{2}匹配的”22”没有被捕获
5.认识 \s \w \d \
/** * 认识 \s \w \d \ * \s 空白字符,包含空格,tab、换行、制表符、回车 * \w 构成单词的字符[a-zA-Z_0-9] * 在java里面字符串\\代表的是一个反斜线\;用正则表达式去匹配一个反斜线\: * 正则表达式本身要匹配一个反斜线的话,需要用两个反斜线; * 然后你要用字符串把这个正则表达式表现出来的时候,每一个反斜线都要用两个反斜线替代; * 在java里面一个反斜线\和后面的字符会合在一起,构成一个转义字符;所以在java里面一个反斜线\必须用两个反斜线来替代; */ p(" \n\r\t".matches("\\s{4}")); p(" ".matches("\\S")); p("a_8".matches("\\w{3}")); p("abc888&^%".matches("[a-z]{1,3}\\d+[&^#%]+")); p("\\".matches("\\\\")); //如果写:p("\\".matches("\\"))的话: //matches("\\")里的\\会被正则表达式认为成它是一个反斜线; //在正则表达式里面,一个\也会是一个特殊字符,它会和后面的字符合在一起,那第一个双引号"又没有配对的了; //所以要在正则表达式里,匹配一个\,要写成:\\\\
true
false
true
true
true
解释:
/**
* 怎么用正则表达式匹配一个反斜线呢?
* 在java里面 一个\必须用两个\\来替代。
* 正则表达式本身要匹配一个反斜线,使用\\来匹配的,然后你要用字符串把这个正则表达式表现出来的时候,每一个\都要用两个\\替代;
* 所以要在正则表达式里面匹配一个反斜线,写4个\
*/
其他的预定义字符类:
6.POSIX Style风格:
//POSIX Style //参考API \p{Lower} A lower-case alphabetic character: [a-z] p("a".matches("\\p{Lower}")); //true
6.boundary 边界匹配:
/** * boundary 边界匹配 * ^ 位于[]外面,代表开头 * \b 一个单词的边界;单词边界:空格、空白字符、各种各样的特殊字符、换行的时候等等,都算单词边界; */ p("hello sir".matches("^h.*")); //true p("hello sir".matches(".*ir$")); //true p("hello sir".matches("^h[a-z]{1,3}o\\b.*")); //true p("hellosir".matches("^h[a-z]{1,3}o\\b.*")); //false
7.匹配空白行:
/** * white lines空白行: */ //以空白字符开头的并且不是换行符,紧跟0个或多个,以换行符结尾; p(" \n".matches("^[\\s&&[^\\n]]*\\n$")); //true
8.匹配Email地址:
/** * 匹配Email地址的正则表达式 * 构成单词的字符或者是.- 出现1次或多次 @ 单词字符或.- 1次或多次 . 单词字符或.- 1次或多次 * 注意.是元字符代表任意字符,这里表示.要用 \\. 代表 */ p("asdfasdfsafsf@dsdfsdf.com".matches("[\\w[.-]]+@[\\w[.-]]+\\.[\\w]+")); //true
.写在[ ]里面表示. [.-]表示.或者-
例子:
p("ab4com".matches("[a-z]{2}[.]{1}\\w{3}")); ——false,因为要求两个a-z的字母后面紧接的是. 所以false
9.matches()、find()、lookingAt():
/** * matches find lookingAt * matches 是否匹配 matches()永远是匹配整个字符串 * m.find(): 找一个和模式相匹配的子串;是找子串,而不是匹配整个字符串; * 找着一个之后,正则引擎会将找到的子串截掉,然后从剩下的字符串里再找; * lookingAt(): 每次找,都是从开头位置找; */ Pattern p = Pattern.compile("\\d{3,5}"); String s = "123-34345-234-00"; Matcher m = p.matcher(s); p(m.matches()); //false p(m.find()); //true p(m.find()); //true p(m.find()); //false p(m.find()); //false //上面的结果解释: //m.matches()运行时,开始分析"123-34345-234-00",分析到123-发现已经不匹配了,停止,返回false; //m.find()执行,继续从34345-234-00开始找,find第一个34345返回true;find第二个234返回true,后面两个false
1 /** 2 * start():找到的字符串的起始位置; 3 * end(): 找到的字符串的结束位置;是找到的字符的后面一个位置; 4 * 必须能够找到,否则打印会报错; 5 */ 6 Pattern p = Pattern.compile("\\d{3,5}"); 7 String s = "123-34345-234-00"; 8 Matcher m = p.matcher(s); 9 p(m.matches()); //false 10 m.reset(); 11 p(m.find()); //true 12 p(m.start() + "-" + m.end()); //0-3 13 14 p(m.find()); //true 15 p(m.start() + "-" + m.end()); //4-9 16 17 p(m.find()); //true 18 p(m.start() + "-" + m.end()); //10-13 19 20 p(m.find()); //false 21 22 p(m.lookingAt()); //true 23 p(m.lookingAt()); //true 24 p(m.lookingAt()); //true 25 p(m.lookingAt()); //true 26 27 //上面结果解释: 28 //m.matches()执行,分析到123-发现已经不匹配了,停止,返回false; 29 //m.reset()执行,m又回到了"123-34345-234-00"的开头位置。从头开始分析(回到初始的状态); 30 //m.lookingAt():每次从开头位置找,每次找到123,就都返回true
10.replacement:
1 /** 2 * replacement 3 * group(): 输出匹配到的子串;整个的正则表达式可以看作组号为0的一个组; 4 */ 5 //将下面的字符串中java全都替换成大写的: 6 Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE); 7 Matcher m = p.matcher("java Java JAVa JaVa IloveJAVA you hateJava"); 8 p(m.replaceAll("JAVA"));
JAVA JAVA JAVA JAVA IloveJAVA you hateJAVA
1 //将下面字符串中,找到的java,第奇数个替换成JAVA,第偶数个替换成java 2 Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE); 3 Matcher m = p.matcher("java Java JAVa JaVa IloveJAVA you hateJava afasdfasdf"); 4 StringBuffer buf = new StringBuffer(); 5 int count = 0; 6 while(m.find()){ 7 count++; 8 if(count%2 == 0){ 9 m.appendReplacement(buf, "java"); 10 }else{ 11 m.appendReplacement(buf, "JAVA"); 12 } 13 } 14 m.appendTail(buf); 15 p(buf);
JAVA java JAVA java IloveJAVA you hatejava afasdfasdf
11.分组:group:
1 /** 2 * group 分组 3 * group(): 返回整个正则表达式所匹配的子串; 4 */ 5 Pattern p = Pattern.compile("\\d{3,5}[a-z]{2}"); 6 String s = "123aa-34345bb-234cc-00"; 7 Matcher m = p.matcher(s); 8 while(m.find()) { 9 p(m.group()); 10 }
123aa
34345bb
234cc
1 //将上面字符串中,匹配的3-5位的数字拿出来: 2 //要知道第几组:数左边的小括号,第一个小括号为第1组,第二个小括号为第2组... 3 Pattern p = Pattern.compile("(\\d{3,5})([a-z]{2})"); 4 String s = "123aa-34345bb-234cc-00"; 5 Matcher m = p.matcher(s); 6 while(m.find()){ 7 p(m.group(1)); 8 }
123
34345
234
12.抓取网页Email地址的例子:
1 package com.cy.regexp; 2 3 import java.io.BufferedReader; 4 import java.io.BufferedWriter; 5 import java.io.FileNotFoundException; 6 import java.io.FileReader; 7 import java.io.FileWriter; 8 import java.io.IOException; 9 import java.util.regex.Matcher; 10 import java.util.regex.Pattern; 11 12 public class EmailSpider { 13 14 @SuppressWarnings("resource") 15 public static void main(String[] args) { 16 try { 17 BufferedReader br = new BufferedReader(new FileReader("D:\\fromEmail.html")); 18 BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\findEmail.txt")); 19 20 String line = ""; 21 while((line = br.readLine()) != null){ 22 writeToFile(line, bw); 23 } 24 bw.flush(); 25 } catch (FileNotFoundException e) { 26 e.printStackTrace(); 27 } catch (IOException e) { 28 e.printStackTrace(); 29 } 30 } 31 32 public static void writeToFile(String line, BufferedWriter bw) throws IOException{ 33 Pattern p = Pattern.compile("[\\w[.-]]+@[\\w[.-]]+\\.[\\w]+"); 34 Matcher m = p.matcher(line); 35 while(m.find()){ 36 bw.write(m.group()); 37 bw.newLine(); 38 } 39 } 40 }
13.修饰符、限定词:
1 /** 2 * qulifiers 修饰符 限定词 在数量后面 加限定词 3 * Greedy quantifiers 贪婪的;默认的写法都是贪婪的;x? x* x+ x{n} x{n,} x{n,m}都是贪婪的 4 * Reluctant quantifiers: 勉强的,非贪婪的,和Greedy正好相反:x?? x*? x+? ... 5 * Possessive quantifiers: 独占的;和贪婪的类似,.{3,10}+,一下吞进去10个字符,不匹配时但是不往外吐,就是找不着; 6 */ 7 8 Pattern p = Pattern.compile(".{3,10}[0-9]"); 9 String s = "aaaa5bbbb6"; 10 Matcher m = p.matcher(s); 11 if(m.find()){ 12 p(m.start() + "-" + m.end()); //0-10 13 }else{ 14 p("not match!"); 15 } 16 17 Pattern p = Pattern.compile(".{3,10}?[0-9]"); 18 String s = "aaaa5bbbb6"; 19 Matcher m = p.matcher(s); 20 if(m.find()){ 21 p(m.start() + "-" + m.end()); //0-5 22 }else{ 23 p("not match!"); 24 } 25 26 Pattern p = Pattern.compile(".{3,10}+[0-9]"); 27 String s = "aaaa5bbbb6"; 28 Matcher m = p.matcher(s); 29 if(m.find()){ 30 p(m.start() + "-" + m.end()); 31 }else{ 32 p("not match!"); //not match! 33 } 34 35 Pattern p = Pattern.compile(".{3,10}+[0-9]"); 36 String s = "aaaa5bbbb68"; 37 Matcher m = p.matcher(s); 38 if(m.find()){ 39 p(m.start() + "-" + m.end()); //0-11 40 }else{ 41 p("not match!"); 42 }
14.non-capturing groups 非捕获组:
1 /** 2 * non-capturing groups 3 * 非捕获组: 如果符合这个条件就捕获;如果不符合这个条件就不捕获 4 */ 5 //这个正则表达式匹配 3个字母的后面紧跟的是一个a,像这样的才去匹配它;而且这个a不被抓出来 6 // ?=a 不捕获这个a 7 //(?=X) X, via zero-width positive lookahead lookahead从头开始看 8 Pattern p = Pattern.compile(".{3}(?=a)"); 9 String s = "444a66b"; 10 Matcher m = p.matcher(s); 11 while(m.find()) { 12 p(m.group()); //444 13 } 14 15 //前面是a的,3个字母 16 Pattern p = Pattern.compile("(?=a).{3}"); 17 String s = "444a66b"; 18 Matcher m = p.matcher(s); 19 while(m.find()) { 20 p(m.group()); //a66 21 } 22 23 //(?!a) 前面不是a的,3个字母 24 Pattern p = Pattern.compile("(?!a).{3}"); 25 String s = "444a66b"; 26 Matcher m = p.matcher(s); 27 while(m.find()) { 28 p(m.group()); //444 66b 29 } 30 31 //3个字母, 后面不是a 32 Pattern p = Pattern.compile(".{3}(?!a)"); 33 String s = "444a66b"; 34 Matcher m = p.matcher(s); 35 while(m.find()) { 36 p(m.group()); //44a 66b 37 } 38 39 //3个字母,从后往前数,不能是a 40 Pattern p = Pattern.compile(".{3}(?<!a)"); 41 String s = "444a66b"; 42 Matcher m = p.matcher(s); 43 while(m.find()) { 44 p(m.group()); //444 a66 45 } 46 47 //3个字母,从后往前数,是a, 包含a 48 Pattern p = Pattern.compile(".{3}(?<=a)"); 49 String s = "444a66b"; 50 Matcher m = p.matcher(s); 51 while(m.find()) { 52 p(m.group()); //44a 53 }
15.back refenrences 向前引用:
1 /** 2 * back refenrences 3 * 向前引用; 4 * (\\d\\d)匹配两个数字,作为结果;\\1 指的是后面的东西必须和前面第一个group找到的结果一模一样 5 * 第一个group找到的是12,后面是12,和前面第1个group找到的东西一样, 所以返回true 6 */ 7 Pattern p = Pattern.compile("(\\d\\d)\\1"); 8 String s = "1212"; 9 Matcher m = p.matcher(s); 10 p(m.matches()); //true 11 12 //第2个group抓到的是2,后面的结果要和第2个group抓到的内容一样 13 Pattern p = Pattern.compile("(\\d(\\d))\\2"); 14 String s = "122"; 15 Matcher m = p.matcher(s); //true 16 p(m.matches());
16.flags的简写:
1 /** 2 * flags的简写 3 * DOTALL .可以匹配所有的字符,默认的.是不匹配换行符的; 4 * CASE_INSENSITIVE 忽略大小写 5 * API: Case-insensitive matching can also be enabled via the embedded flag expression (?i). 6 */ 7 Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE); 8 9 //(?i) 也是非捕获组 跟上面的写法一模一样,上面写法的简写 10 p("Java".matches("(?i)(java)")); //true
关于(?i)不区分大小写的示例:
(?i)abc 表示abc都忽略大小写 a(?i)bc 表示bc忽略大小写 a((?i)b)c 表示只有b忽略大小写
fileSuffix.matches("(?i)png|jpg|bmp|jpeg|pdf") 校验文件后缀名只能是:png、jpg、bmp、jpeg、pdf,且不区分大小写
--