正则表达式

	//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%。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值