//greedy quantifiers ,能多不少
Pattern p = Pattern.compile(".{2,5}\\d");
String input = "aa3bb4c";
Matcher m = p.matcher(input);
if(m.find())
p(m.group()); //结果:aa3bb4
//reluctant quantifiers ,能少不多
Pattern p = Pattern.compile(".{2,5}?\\d");
String input = "aa3bb4c";
Matcher m = p.matcher(input);
if(m.find())
p(m.group()); //结果:aa3
//Possessive quantifiers ,这个比较特别
Pattern p = Pattern.compile(".{2,5}+\\d");
String input = "aa3";
Matcher m = p.matcher(input);
if(m.find())
p(m.group()); //结果:空
Pattern p = Pattern.compile(".{2,5}+\\d");
String input = "aa3bbb4";
Matcher m = p.matcher(input);
if(m.find())
p(m.group()); //结果:a3bbb4
一个字符串将其中的数字换成“-”,一般的做法是比较每个char然后再替换
String s = "ad233dd";
StringBuffer sb = new StringBuffer();
sb.append(s);
for(int i=0;i<s.length();i++){
if((int)s.charAt(i) >= 48 && (int)s.charAt(i) <=57){
sb.replace(i, i+1, "-");
}
}
s = sb.toString();
但用正则表达式,一句话就搞定
String s = "ad233dd";
s = s.replaceAll("\\d", "-");
(java中反斜杠\和它后边的字符组合在一起表示“转义”字符)
Pattern p = Pattern.compile("[a-z]{3}"); //compile 目的是为了匹配起来更快
Matcher m = p.matcher("abc");
boolean b = m.matches();
"abc".matches("[a-z]{3}"); //这一句话效果上和上面三句是一样的,但上面的也有其优点
static void p(Object o){
System.out.println(o);
}
p("aa".matches("aa")); //regex 也可以是正常字符 true
p("aaaaa".matches("a*")); // * 表示0个或多个 true
p("".matches("a*")); // true
p("b".matches("a*")); // false
p("a".matches("a+")); // + 表示1个或多个 true
p("".matches("a+")); // false
p("".matches("a?")); // ? 表示1个或0个 true
p("a".matches("a?")); //true
p("aa".matches("a?")); //false
p("aa".matches("a{2}")); // {n} 正好n个 true
p("aaa".matches("a{2}")); //false
p("a".matches("a{2,}")); // false x{n,} 最少n个
p("aaa".matches("a{2,}")); // true
p("a".matches("a{2,4}")); // false x{n,m} 最少n个 最多m个
p("aa".matches("a{2,4}")); //true
p("aaa".matches("a{2,4}")); //true
p("aaaa".matches("a{2,4}")); //true
p("aaaaa".matches("a{2,4}")); //false
//范围
p("a".matches("[a-d]")); //a到d中的一个
p("a".matches("[b-f]"));
p("a".matches("[^abc]")); //非abc中的任何字符
p("a".matches("[a-zA-Z]")); //a到z或者A到Z
p("a".matches("[a-z[A-Z]]")); //a到z或者A到Z
p("d".matches("[a-z&&[def]]")); //def中的一个
p("b".matches("[a-z&&[^bcd]]")); //a到z中不是bcd的字符
p("a".matches("[a-z&&[^bcd]]"));
//认识 . /s /S /d /D /w /W /
p("234".matches("[\\d]{1,2}")); // \d [0-9]0到9的数字 \D [^0-9] false
p("d".matches("\\D")); //true
p(" ".matches("\\s")); // \s 空格 [\t\n\x0B\f\r] \S 非空格 true
p("sdd".matches("[\\w]{3}")); // \w [a-zA-Z_0-9] true
p("sdd".matches("[a-zA-Z_0-9]{3}")); // \w [a-zA-Z_0-9] true
p("\\".matches("\\\\")); //java中 一个\ 要和它后边的字符构成转义字符 ,所以要表示一个\ ,就要用\\来表示 true
//正则表达式要表示一个\ ,需要用2个\\来表示,要表示2个\\,所以需要用4个\来表示
//边界
p("hello sir".matches("^h.*")); //^在[]里面[^]表示取反,在[]外则表示一行的开始 true
p("hello sir".matches(".*ir$")); // $ 一行的结尾 true ,注意是“行”以ir结尾的,如果改成“hello siraaa”则为false, ^ 行的开始,$行的结尾
p(" \n".matches("^[\\s&&[^\\n]]*\\n$")); //一个或多个空白字符,然后换行 true
// matches reset find lookingAt 使用
Pattern p = Pattern.compile("\\d{3,5}");
String s = "23-22222-33-777";
Matcher m = p.matcher(s);
p(m.matches()); //matches() 匹配整个字符串 false
m.reset(); // 执行matches()后,“匹配器”会吃进几个字符,当遇到不符合pattern的字符时就停下来,reset()即将吃进的吐出来,恢复到初始状态
p(m.find()); // find() 在字串中找是否有符合pattern的 true
p(m.start()+"-"+m.end()); //start() 被找见的子串的开始的位置,end() 结束的位置
p(m.find());// true
p(m.start()+"-"+m.end());
p(m.find());// false
p(m.lookingAt()); //总是从头开始匹配 false
p(m.lookingAt()); // false
p(m.lookingAt());// false
//Matcher 用法 group() replaceAll()
Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
String s = "java Java JaVa ilovejaVA aaa";
Matcher m = p.matcher(s);
while(m.find())
p(m.group()); //group() 结果等同于s.subString(m.start(),m.end())
p(m.replaceAll("*")); //replaceAll() 替换所有找到的字串为*
//Matcher 奇数的java替换成* 偶数的替换成-
Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE);
String s = "bbjavac Javac JaVa ilovejaVA aaa";
Matcher m = p.matcher(s);
StringBuffer sb = new StringBuffer();
int i = 0;
while(m.find()){ //find() appendReplacement() appendTail() 一般组合使用
i++;
if(i%2 == 0){
m.appendReplacement(sb, "-");
}else{
m.appendReplacement(sb, "*");
}
p(m.start()+"-"+m.end());
p("i="+i+","+sb);
}
m.appendTail(sb);
p(sb);
//取出匹配p的字串中的数字
Pattern p = Pattern.compile("\\d{3,5}[a-zA-Z]{2}");
String s = "234aab =55555ccll*222cc*";
Matcher m = p.matcher(s);
Pattern p2 = Pattern.compile("\\d{3,5}");
while(m.find()){
String ss = m.group();
Matcher m2 = p2.matcher(ss);
while(m2.find()) //再循环去取
p(m2.group());
}
//取出匹配p的字串中的数字 用()分组
Pattern p = Pattern.compile("(\\d{3,5})([a-zA-Z]{2})"); //第一个左(所在组的组id是1,以此类推
String s = "234aab =55555ccll*222cc*";
Matcher m = p.matcher(s);
while(m.find()){
p(m.group(1)); //本身符合p的字串是一个组group(0),group(1)是第一个()组,group(2)是第二个()组
}
// . \\. 的使用
p(".".matches(".")); // 只有一个.表示一个任意字符 true
p("a".matches(".")); // true
p("ab".matches(".")); // false
p("ab".matches(".*")); // true
p(".".matches("\\.")); // 要表示就是一个. 而不代表任意字符 在.前加\\ true
p("a".matches("\\.")); // 要表示就是一个. 而不代表任意字符 在.前加\\ false
//邮件地址爬虫
static void getEmailAdd() throws IOException{
File f = new File("d://email.txt");
BufferedReader br = new BufferedReader(new FileReader(f));
String temp = null;
while((temp = br.readLine()) != null){
parse(temp);
}
br.close();
}
private static void parse(String temp) {
Pattern p = Pattern.compile("[\\w-[^\\s]]+@[\\w[^\\s]]+\\.[\\w[^\\s]]+",Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(temp);
while(m.find())
p(m.group());
}
p("*ss".matches("^\\*\\..*")); //以*. 开头的字符串 false
p("*ss".matches("^[\\*\\.].*")); //以*. 中的任意一个开头的字符串 true
//统计代码中的空行,注释行,代码行
static void statisticCodeLines() throws IOException{
File f = new File("d://src");
File[] fs = f.listFiles();
Map<String,Integer> map = new HashMap<String,Integer>();
for(File child : fs){
if(child.getName().matches(".*\\.java$")){ //统计 后缀是.java的文件 ,也可以用 endWith()
parse(child,map);
}
}
Set<String> keys = map.keySet();
Iterator<String> it = keys.iterator();
while(it.hasNext()){
String next = it.next();
p(next+":"+map.get(next));
}
}
private static void parse(File child,Map<String,Integer> map) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(child));
String temp = null;
while((temp = br.readLine()) != null){ //readLine() 返回的String中已经将换行符给去掉,只包含内容
temp = temp.trim(); //trim() 将开头与结尾的空白字符去掉
if(temp.matches("[\\s&&[^\\n]]*")){ //空行
if(null == map.get("空行")){
map.put("空行", 1);
}else{
map.put("空行", map.get("空行") + 1);
}
}else if(temp.matches("^//.*") || temp.matches("^/\\*.*") || temp.matches("^\\*.*")){ //注释行
//else if(temp.matches("^//.*") || temp.startsWith("/*") || temp.startsWith("*")){ // startWith() 也可以
if(null == map.get("注释行")){
map.put("注释行", 1);
}else{
map.put("注释行", map.get("注释行") + 1);
}
}else{ //代码行
if(null == map.get("代码行")){
map.put("代码行", 1);
}else{
map.put("代码行", map.get("代码行") + 1);
}
}
}
}
//greedy quantifiers ,能多不少
Pattern p = Pattern.compile(".{2,5}\\d");
String input = "aa3bb4c";
Matcher m = p.matcher(input);
if(m.find())
p(m.group()); //结果:aa3bb4
//reluctant quantifiers ,能少不多
Pattern p = Pattern.compile(".{2,5}?\\d");
String input = "aa3bb4c";
Matcher m = p.matcher(input);
if(m.find())
p(m.group()); //结果:aa3
//Possessive quantifiers ,这个比较特别
Pattern p = Pattern.compile(".{2,5}+\\d");
String input = "aa3";
Matcher m = p.matcher(input);
if(m.find())
p(m.group()); //结果:空
Pattern p = Pattern.compile(".{2,5}+\\d");
String input = "aa3bbb4";
Matcher m = p.matcher(input);
if(m.find())
p(m.group()); //结果:a3bbb4
// non-capturing group
Pattern p = Pattern.compile(".{3}(?=a)"); //以a结束,前面有三个字符
String input = "444a66b";
Matcher m = p.matcher(input);
while(m.find())
p(m.group()); //444
// non-capturing group
Pattern p = Pattern.compile("(?=a).{3}"); //以a打头,包含a在内有3个字符
String input = "444a66b";
Matcher m = p.matcher(input);
while(m.find())
p(m.group()); //a66
//表示某几个数字中的一个
p("35".matches("35|50")); //35,50中的一个 true
p("3".matches("35|50")); //false
p("35".matches("[35|50]")); // 3,5,0的一个 ,和[350]效果一样 false
p("35".matches("[350]")); // false
p("3".matches("[350]")); // true
//下面的正则表示的是135,50,86加8个数字的 中的一个
Pattern p = Pattern.compile("^135|50|86\\d{8}");
p(p.matcher("13593250698").matches()); //false
p(p.matcher("135").matches()); //true
p(p.matcher("50").matches()); //true
//135,150,186段的电话号码
Pattern p = Pattern.compile("^1(35|50|86)\\d{8}");
String s = "18893254998";
Matcher m = p.matcher(s);
p(m.matches());
// \d 表示的是 0-9的数字 ,等于[0-9]
p("-1".matches("\\d")); // false
p("1".matches("\\d"));// true
p("11".matches("\\d"));// false
//非负整数
p("0".matches("\\d+"));// true
//正整数
p("0".matches("[\\d&&[^0]]\\d*"));// false
p("20".matches("[\\d&&[^0]]\\d*"));// true
p("20".matches("(\\d&&[^0])\\d*"));// []表示范围,()表示分组,似乎&&只用在[]中 false
p("20".matches("[1-9]\\d*"));// true
//非正整数
p("-980".matches("0|^-\\d+"));
p("哈".matches("[\\u4e00-\\u9fa5]")); //true 匹配中文字符
p("哈看的哈".matches("[\\u4e00-\\u9fa5]+")); //true 匹配中文字符串
p("哈看的哈dd".matches("[\\u4e00-\\u9fa5]+")); //false
p("10000".matches("[1-9]\\d{4,}")); //true 匹配腾讯QQ号,从10000开始,最少5位
p("1000099".matches("[1-9]\\d{4,}")); //true
p("1".matches("\\d{,3}")); //报错 !
p("1".matches("\\d{0,3}")); //true 最多3位
//将字符串中的钱数找出来
Pattern p = Pattern.compile("(\\d+\\.?\\d*)元");
String s = "23元坎坎坷坷88看看66.23元";
Matcher m = p.matcher(s);
while(m.find())
p(m.group(1));
//BufferedReader 的 readLine() 方法会把换行符去掉
//A String containing the contents of the line, not including any line-termination characters,
//or null if the end of the stream has been reached
// "." 表示除换行符外的任意字符 ,\b word边界 boundry
Pattern p = Pattern.compile("\\bhi\\b.*\\bLucy\\b",Pattern.CASE_INSENSITIVE);
String s = "hi,this is him,he always says 'Hi,\r\nLucy,How are you'";
String s1 = "hi,this is him,he always says 'Hi,Lucy,How are you'";
Matcher m = p.matcher(s);
Matcher m1 = p.matcher(s1);
p(m.find()); //false
p(m1.find()); //true
//找出以g开头的单词(不区分大小写)
Pattern p = Pattern.compile("\\bg\\w*\\b",Pattern.CASE_INSENSITIVE);
String s = "he said this is good,but GoodMan didn't think so";
Matcher m = p.matcher(s);
while(m.find())
p(m.group());
// ^g.*d$ 表示整行或整个字符串要以g开头,d结尾,中间包含任意个不是换行符的字符
// g.*d 表示字符串中包含g打头d结尾的字符串
Pattern p = Pattern.compile("^g.*d$",Pattern.CASE_INSENSITIVE);
String s = "gooxxd";
Matcher m = p.matcher(s);
while(m.find())
p(m.group()); //goodxxd
Pattern p = Pattern.compile("g.*d",Pattern.CASE_INSENSITIVE);
String s = "he said this is good,but GoooooodMan didn't think so";
Matcher m = p.matcher(s);
while(m.find())
p(m.group()); // good,but GoooooodMan did
// 要表示正则中的元字符,比如:.、*、(等,需要转义
p(".hha ss*".matches("^\\..*\\*$")); //true 表示以.开头,以*结尾,中间是除换行外的任意字符
p(".hha ss".matches("^\\..*\\*$")); //false
//分枝条件 正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开
//这个可以表示(010)12345678 010-12345678 010 12345678 3位区号加8位的电话号码,
//但也可以表示这种 010)-12345678 不正确的电话格式
Pattern p = Pattern.compile("\\(?0\\d{2}\\)?[) -]?\\d{8}");
String s1="010)-12345678";
Matcher m0 = p.matcher(s1);
p(m0.matches()); //true
//用分枝条件解决这个问题
Pattern p2 = Pattern.compile("\\(0\\d{2}\\)\\d{8}|0\\d{2}[- ]?\\d{8}");
String s2="011 12345678";
String s3="011-12345678";
Matcher m1 = p2.matcher(s1);
Matcher m2 = p2.matcher(s2);
Matcher m3 = p2.matcher(s3);
p(m1.matches()); //false
p(m2.matches());//true
p(m3.matches());//true
//分组,重复单个字符直接在单个字符后面加上限定符就可以,如果要重复多个字符可以用分组,()后加上限定符。而且分组的功能不限于此
//匹配ip地址
Pattern p2 = Pattern.compile("((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)");
String ip = "0.25.139.195"; //true
String ip2 = "256.300.888.999"; //false
//表示0-199的数
Pattern p = Pattern.compile("[01]?\\d\\d?");
p(p.matcher("0").matches());
p(p.matcher("3").matches());
p(p.matcher("99").matches());
p(p.matcher("199").matches());
p(p.matcher("200").matches()); //false
//反义
//表达不属于某个能简单定义的字符类的字符
// \W 不是字母数字下划线 ,\S 不是空白字符,\B 不是单词开头结束的位置 ,\D 不是数字 ,[^a] 除a外的任意字符,[^aeiou] 除aeiou外的任意字符
Pattern p = Pattern.compile("<a[^>]+>"); //用尖括号括起来的以a开头的字符串
p(p.matcher("<aa>").matches()); //true
p(p.matcher("<a>").matches()); //false
//后向引用
//用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本 (不用后向引用,还真不好表示重复啊!)
// () 表示分组,以(为基准,第一个(为组1,第二个(为组2
Pattern p2 = Pattern.compile("\\b(\\w+)\\b\\s+\\1\\b");
Pattern p2 = Pattern.compile("\\b(?<gw>\\w+)\\b\\s+\\k<gw>\\b"); //自定义组名 (?<name>exp) 或者 (?'name'exp),后向引用 \k<name>
p(p2.matcher("aa aa").matches()); //true
p(p2.matcher("1 1").matches()); //true
p(p2.matcher("11 21").matches()); //false
//零宽断言
// (?=exp) 断言自身出现的位置的后面能匹配表达式exp
Pattern p = Pattern.compile("\\b\\w+(?=ing\\b)"); //以ing结尾的单词的前面的部分,即不包含ing
// Pattern p = Pattern.compile("\\b\\w+(?=ing)\\b"); //为什么这个不可以呢,和上面的区别在哪里?
String s = "I'm singing while you're dancing";
Matcher m = p.matcher(s);
while(m.find())
p(m.group()); //sing danc
// (?<=exp) 断言自身出现的位置的前面能匹配表达式exp
Pattern p = Pattern.compile("(?<=\\bre)\\w+\\b"); //以re开头的单词的后面的部分,即不包含re
String s = "I'm readding a book";
Matcher m = p.matcher(s);
while(m.find())
p(m.group()); // adding
// 给一个很长的数字中每三位间加一个逗号
StringBuffer sb = new StringBuffer();
String s = "1234567890";
String r = dealNumber(s,new StringBuffer()).toString();
p(r); // 1,234,567,890
static StringBuffer dealNumber(String s,StringBuffer sb){
Pattern p = Pattern.compile("((?<=\\d)\\d{3})+\\b"); //3位,3位 从右往左数
Matcher m = p.matcher(s);
if(m.find()){
sb.append(s.substring(0, m.start())+",");
dealNumber(m.group(),sb);
}
else{
sb.append(s);
}
return sb;
}
//负向零宽断言
// (?!exp) 断言此位置后面不能匹配表达式exp (?<!exp) 断言此位置前面不能匹配表达式exp
//要查找字母q后面不是u的单词。 “\\b\\w*q[^u]\\w*\\b” 当q位于开头及中间时是正确的,当q位于末尾时就出错了
p("qty".matches("\\b\\w*q[^u]\\w*\\b")); //true
p("query".matches("\\b\\w*q[^u]\\w*\\b")); //false
p("Iraq fighting".matches("\\b\\w*q[^u]\\w*\\b")); //true q[^u] 要匹配后面不是u的字符,就把空格算作那个字符
p("Iraq fighting".matches("\\b\\w*q(?!u)\\w*\\b")); //false 负向零宽断言 它只匹配一个位置,并不消费任何字符
//匹配不包含连续字符串abc的单词
p("dabcd".matches("\\b((?!abc)\\w)+\\b")); //false
p("dbcd".matches("\\b((?!abc)\\w)+\\b")); //true
p("abcd".matches("\\b((?!abc)\\w)+\\b")); //false
p("dabc".matches("\\b((?!abc)\\w)+\\b")); //false ,(?!abc)\\w 这个不是应该表示\w之前不是连续字符abc的吗,之后的也能表示的了?
//前面不是小写字母的七位数字
p("a1234567".matches("(?<![a-z])\\d{7}"));//false
p("01234567".matches("(?<![a-z])\\d{7}"));//false
p("1234567".matches("(?<![a-z])\\d{7}"));//true
p("A1234567".matches("(?<![a-z])\\d{7}"));// 应该是true才对呀,为什么是false呢?
//不包含属性的简单HTML标签内里的内容
//(?<=<(\\w{0,"+(Integer.MAX_VALUE-1)+"})>) 被尖括号括起来的单词
// 对 / 转义,\1 反向引用组1的内容
//捕获的是<b></b>之间的内容 ,不包括前缀和后缀本身
Pattern p = Pattern.compile("(?<=<(\\w{0,"+(Integer.MAX_VALUE-1)+"})>).*(?=<\\/\\1>)");
String s = "<b>haha</b>";
Matcher m = p.matcher(s);
while(m.find())
p(m.group()); //haha
//注释 (?#comment)
Pattern p = Pattern.compile("2[0-4]\\d(?#200-249)|25[0-5](?#250-255)|[01]?\\d\\d?(?#0-199)");
//贪婪 ,尽可能多的匹配
//懒惰,尽可能少的匹配, 在贪婪的限定符后加 ?
// *?,+?,??,{n,m}?,{n,}?
看完了马士兵老师讲的正则表达式,感觉上掌握了有60%的东西,剩下的还需要以后实际使用中再体会和总结。
通过不断练习感觉掌握程度达到了70%。