Java正则表达式总结

Java正则表达式总结

持续更新中ing


最近看了下Java正则表达式,有些收获,于是写在这里。

一 、简介

Java的正则表达式是由java.util.regex的Pattern和Matcher类实现的java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包。(参考自:http://blog.csdn.net/allwefantasy/article/details/3136570 ,原文有很多问题,忍不住自己整理一下)

作用
PatternPattern是一个正则表达式经编译后的表现模式。
MatcherMatcher对象是一个状态机器,它依据Pattern对象做为匹配模式对字符串展开匹配检查。

1、Pattern类


返回值方法说明
static Patterncompile(String regex)将给定的正则表达式编译并赋予给Pattern类
static Patterncompile(String regex, int flags)同上,但增加flag参数的指定,可选的flag参数包括:CASE INSENSITIVE,MULTILINE,DOTALL,UNICODE CASE, CANON EQ
intflags()返回当前Pattern的匹配flag参数.
Matchermatcher(CharSequence input)生成一个给定字符串的Matcher对象
static booleanmatches(String regex, CharSequence input)编译给定的正则表达式并且对输入的字串以该正则表达式为模开展匹配,该方法适合于该正则表达式只会使用一次的情况,也就是只进行一次匹配工作,因为这种情况下并不需要生成一个Matcher实例。
Stringpattern()返回该Patter对象所编译的正则表达式。
String[]split(CharSequence input)将目标字符串按照Pattern里所包含的正则表达式为模进行分割。
String[]split(CharSequence input, int limit)作用同上,增加参数limit目的在于要指定分割的段数,如将limi设为2,那么目标字符串将根据正则表达式分为割为两段。

2、Matcher类


返回值方法说明
MatcherappendReplacement(StringBuffer sb, String replacement)将当前匹配子串替换为指定字符串,并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里。
StringBufferappendTail(StringBuffer sb)将最后一次匹配工作后剩余的字符串添加到一个StringBuffer对象里。
intend()返回当前匹配的子串的最后一个字符在原目标字符串中的索引位置 。
intend(int group)返回与匹配模式里指定的组相匹配的子串最后一个字符的位置。
booleanfind()尝试在目标字符串里查找下一个匹配子串。
booleanfind(int start)重设Matcher对象,并且尝试在目标字符串里从指定的位置开始查找下一个匹配的子串。
Stringgroup()返回当前查找而获得的与组匹配的所有子串内容
Stringgroup(int group)返回当前查找而获得的与指定的组匹配的子串内容
intgroupCount()返回当前查找所获得的匹配组的数量。
booleanlookingAt()检测目标字符串是否以匹配的子串起始。
booleanmatches()尝试对整个目标字符展开匹配检测,也就是只有整个目标字符串完全匹配时才返回真值。
Patternpattern()返回该Matcher对象的现有匹配模式,也就是对应的Pattern 对象。
StringreplaceAll(String replacement)将目标字符串里与既有模式相匹配的子串全部替换为指定的字符串。
StringreplaceFirst(String replacement)将目标字符串里第一个与既有模式相匹配的子串替换为指定的字符串。
Matcherreset()重设该Matcher对象。
Matcherreset(CharSequence input)重设该Matcher对象并且指定一个新的目标字符串。
intstart()返回当前查找所获子串的开始字符在原目标字符串中的位置。
intstart(int group)返回当前查找所获得的和指定组匹配的子串的第一个字符在原目标字符串中的位置。

二 、实例

上面的简介并不能让人熟练使用正则表达式,下面通过实例,增加对Java正则表达式的掌握程度。
如果,不熟悉正则的语法,可以拉到本页最下面,有详细的语法介绍。


1、语法实践

以下这段代码我忘记在哪找的了,它实践了一下正则表达式的部分功能。如果你逐一运行一下,对正则的语法就能掌握个大概了。

package com.lvb.regex;

import java.util.Arrays;
import java.util.regex.Pattern;

/** 
 * 正则表达式:
 *1、元字符 好比char,紧紧代表一个字符;
 *2、某些字符,比如\、.、*等这样的字符在正则表达式中已经被作为标记使用了,如果你想作为非元字符使用的话就得进行转义,转义的方法是在这些字符前面加\,
 * 比如\就变成\\,.就成为\.
 *3、重复的元字符:*,+,?,{n},{n,},{n,m},这个标记是用来修饰它前面的那个字符的。
 *4、字符类,或称为分组[],比如[0-9],[0-9A-Za-z]用-表示范围
 */
public class PatternDemo {
	public static void main(String[] args) {
		/**
		 1、元字符的[]
		 */
		//[]属于元字符系列,所谓元字符简单的说就是字符,就是一个char,像bc就不是一个char了
		//method2(new String[] { "abt", "act", "adt", "abct", "bt" }, "a[bcd]t");
		//[]的区间,-的两头代表区间,多区间这样写,比如[0-9a-zA-Z]
		//		method2(new String[] { "a1t", "a3t", "a01t", "abt", "2t" }, "a[0-9]t");
		//补集用^表示,在二元运算符中这是非的意思,尽管用了^,at还是不能通过,所以元字符[]必须有且仅有一个字符
		//		method2(new String[] { "a0t", "a2t", "abt", "at" }, "a[^0246]t");

		/**
		 2、元字符的? + *
		 */
		//?的目标是它前面的一个字符,元字符?表示它前面的一个字符出现0次或1次
		//		method2(new String[] { "", "a", "aa", "at", "a1t" }, "a?");
		//元字符+的目标是它前面的一个字符,它表示它前面的那个字符出现1次或多次
		//		method2(new String[] { "", "a", "aa", "aaaaa", "at", "a1t" }, "a+");
		//元字符*的目标是它前面的一个字符,它表示它前面那个字符出现0次或多次,*可以说是?和+的并集
		//      method2(new String[]{"","a","aa","aaaaa","at","a1t"}, "a*");

		/**
		 .元字符能匹配任何字符(换行\r除外),所以用.*可以匹配换行外的任何字符串
		 */
		//method2(new String[] { "", "a", "aa", "aaaaa", "at", "a1t", "\t", "\r", "n" }, ".");
		//      method2(new String[]{"","a","aa","aaaaa","at","a1t","\t","\r","n"}, ".*");

		/** 数量{n},{n,},{n,m}*/
		//{n}表示它前面的字符重复n次,并且只重复n次,重复n-1次或n+1次都是不可以的
		//      method2(new String[]{"","a","aa","aaaaa","at","a1t"}, "a{2}");
		//{n,}是对{n}的扩展,表示重复n次(包含n次)以上
		//method2(new String[] { "", "a", "aa", "aaaaa", "at", "a1t" }, "a{2,}");
		//{n,m}表示数目在n到m范围内,包含两头
		//		method2(new String[] { "", "a", "aa", "aaa", "aaaa", "aaaaa", "at" }, "a{2,4}");
		//      method2(new String[]{"12345-1234","12345"}, "\\d{5}-\\d{4}|\\d{5}");
		//
		//		method2(new String[] { "12345-123", "12345" }, "\\d{5}|\\d{5}-\\d{4}");
		//		method2(new String[] { "211", "12345" }, "2[0-4]\\d");
		//		method2(new String[] { "1", "12345" }, "[01]?\\d\\d?");
		method2(new String[] { "1", "12345", "12" }, "[0-9]");

	}

	private static void method2(String[] a, String regex) {
		Pattern p = Pattern.compile(regex);
		for (int i = 0; i < a.length; i++) {
			System.out.println(a[i] + "," + p.matcher(a[i]).matches());
		}
	}

	private static void method1() {
		String str = "2011-11-12";
		String pat = "\\d{4}-\\d{2}-\\d{2}";
		System.out.println(Pattern.compile(pat).matcher(str).matches());

		String str1 = "a1b22c333d4444e55555f";
		//按数字来分割
		String[] str1Arr = Pattern.compile("\\d+").split(str1);
		System.out.println(Arrays.toString(str1Arr));
		//数字全部替换成_
		System.out.println(Pattern.compile("\\d+").matcher(str1).replaceAll("_"));
		//去除所有的空格
		System.out.println("\\s去除所有的空格:" + Pattern.compile("\\s").matcher("aa b c d ").replaceAll(""));
		System.out.println("5-10个字符:" + Pattern.compile(".{5,10}").matcher("12345").matches());
		System.out.println("多匹配:" + Pattern.compile("\\bhi.*Lucy\\b").matcher("hi后面不远处跟着一个Lucy").matches());
		System.out.println("多匹配2:" + Pattern.compile("^\\d{5,12}$").matcher("12345678a").matches());

		//直接调用String类提供的方法更加的方便
		System.out.println(Arrays.toString(str1.split("\\d+")));
		System.out.println("2011-11-12".matches("\\d{4}-\\d{2}-\\d{2}"));
	}
}

2、匹配电话号码

现有以下3种模式的电话号码,要求全部匹配出来

(212) 555-1212
212-555-1212
212 555 1212

package com.lvb.regex;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexPractice {
	public static void main(String[] args) {
		RegexPractice practice = new RegexPractice();
		practice.findNum();
	}
	private void findNum() {
		String s = "(212) 555-1212 212-555-1212 212 555 1212";
		//生成Pattern对象,并编译一个正则表达式,正则表达式的解释在下方
		Pattern pattern = Pattern.compile("\\(\\d{3}\\)\\s\\d{3}-\\d{4}");
		//生成Pattern对象,并编译一个正则表达式,正则表达式的解释在下方
		Pattern pattern2 = Pattern.compile("(\\(\\d{3}\\)|\\d{3})\\s?(-|)?\\d{3}\\s?(-|)?\\d{4}");
	        //用Pattern类的matcher()方法生成一个Matcher对象
	        Matcher matcher = pattern2.matcher(s);
		while(matcher.find()) {
			System.out.println(matcher.group());
		}
	}
}

\\(\\d{3}\\)\\s\\d{3}-\\d{4} : 圆括号()在正则表达式中有两层含义,而对java的解释器来说,在反斜线字符\前的字符有特殊的含义,故,我们为了让它们解释为字面上的意思,必须加\,进行转义。\d单字符类型用来匹配从0到9的任何数字,另外{3}重复符号,是个简便的记号,用来表示有3个连续的数字位,也等效于(\d\d\d)。\s用来匹配空格,比如Space键,tab键和换行符。故,此表达式的含义为:(nnn) nnn-nnnn

(\\(\\d{3}\\)|\\d{3})(-| )?\\d{3}(-| )?\\d{4}(\\(\\d{3}\\)|\\d{3}) 字符|表示或的含义,即(nnn)或nnn,区别为有无括号。(-| )?:在()含有|时,它匹配是否含有空格符或连字符,而尾部的?元字符表示有无分隔符的情况。故,此表达式的含义为:

nnn nnn nnnn
nnn-nnn nnnn
nnn nnn-nnnn
nnn-nnn-nnnn
(nnn) nnn nnnn
(nnn)-nnn nnnn
(nnn) nnn-nnnn
(nnn)-nnn-nnnn

所以,pattern2可以匹配要求中的3种电话号码。
但这其实是有问题的,因为正则表达式能够匹配8种模式的号码,而我们只需要3种,那么万一匹配列表中有其他5种不需要的号码,也会被匹配到,这样就违背了我们的初衷,所以这个表达式需要改进。
我们在使用正则表达式时,必须保证表达式的含义是我们需要的。也就是说,表达式匹配到的所有结果,都是我们希望它匹配到的,都是有用的,切记不要出现上面的例子。


3、Pattern类方法实践

一个正则表达式,也就是一串有特定意义的字符,首先必须要编译成为一个Pattern类的实例,这个Pattern对象将会使用 matcher()方法来生成一个Matcher实例,接着便可以使用该 Matcher实例以编译的正则表达式为基础对目标字符串进行匹配工作,多个Matcher是可以共用一个Pattern对象的

Pattern类的方法比较简单,通过下面的小例子来介绍一下:

import java.util.regex.*;
public class Replacement{
      public static void main(String[] args) throws Exception {
        // 生成一个Pattern,同时编译一个正则表达式
        Pattern p = Pattern.compile("[/]+");
        //用Pattern的split()方法把字符串按"/"分割
        String[] result = p.split(
"Kevin has seen《LEON》seveal times,because it is a good film."
+"/ 凯文已经看过《这个杀手不太冷》几次了,因为它是一部"
+"好电影。/名词:凯文。");
        for (int i=0; i<result.length; i++)
            System.out.println(result[i]);
      }
}

输出结果为:

Kevin has seen《LEON》seveal times,because it is a good film.
凯文已经看过《这个杀手不太冷》几次了,因为它是一部好电影。
名词:凯文。

很明显,该程序将字符串按"/"进行了分段,我们以下再使用 split(CharSequence input, int limit)方法来指定分段的段数,程序改动为:
tring[] result = p.split(“Kevin has seen《LEON》seveal times,because it is a good film./ 凯文已经看过《这个杀手不太冷》几次了,因为它是一部好电影。/名词:凯文。”,2);

这里面的参数"2"表明将目标语句分为两段。

输出结果则为:

Kevin has seen《LEON》seveal times,because it is a good film.
凯文已经看过《这个杀手不太冷》几次了,因为它是一部好电影。/名词:凯文。

4、Matcher类方法实践

一个Matcher实例是被用来对目标字符串进行基于既有模式(也就是一个给定的Pattern所编译的正则表达式)进行匹配查找的,所有往Matcher的输入都是通过CharSequence接口提供的,这样做的目的在于可以支持对从多元化的数据源所提供的数据进行匹配工作。

我们分别来看看各方法的使用:

  • 1、 matches()/lookingAt ()/find():
    一个Matcher对象是由一个Pattern对象调用其matcher()方法而生成的,一旦该Matcher对象生成,它就可以进行三种不同的匹配查找操作:

    matches()方法尝试对整个目标字符展开匹配检测,也就是只有整个目标字符串完全匹配时才返回true
    lookingAt ()方法将检测目标字符串是否以匹配的子串起始。
    find()方法尝试在目标字符串里查找下一个匹配子串。

以上三个方法都将返回一个布尔值来表明成功与否。

  • 2、 replaceAll ()/appendReplacement()/appendTail():
    Matcher类同时提供了四个将匹配子串替换成指定字符串的方法:

    replaceAll()
    replaceFirst()
    appendReplacement()
    appendTail()

replaceAll()与replaceFirst()的用法都比较简单,请看上面方法的解释。我们主要重点了解一下appendReplacement()和appendTail()方法。

appendReplacement(StringBuffer sb, String replacement) 将当前匹配子串替换为指定字符串,并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里,而appendTail(StringBuffer sb) 方法则将最后一次匹配工作后剩余的字符串添加到一个StringBuffer对象里。

例如,有字符串fatcatfatcatfat,假设既有正则表达式模式为"cat",第一次匹配后调用appendReplacement(sb,“dog”),那么这时StringBuffer sb的内容为fatdog,也就是fatcat中的cat被替换为dog并且与匹配子串前的内容加到sb里,而第二次匹配后调用appendReplacement(sb,“dog”),那么sb的内容就变为fatdogfatdog,如果最后再调用一次appendTail(sb),那么sb最终的内容将是fatdogfatdogfat。

还是有点模糊?那么我们来看个简单的程序:

//该例将把句子里的"Kelvin"改为"Kevin"
import java.util.regex.*;
public class MatcherTest{
    public static void main(String[] args) 
                         throws Exception {
        //生成Pattern对象并且编译一个简单的正则表达式"Kelvin"
        Pattern p = Pattern.compile("Kevin");
        //用Pattern类的matcher()方法生成一个Matcher对象
        Matcher m = p.matcher("Kelvin Li and Kelvin Chan are both working in Kelvin Chen's KelvinSoftShop company");
        StringBuffer sb = new StringBuffer();
        int i=0;
        //使用find()方法查找第一个匹配的对象
        boolean result = m.find();
        //使用循环将句子里所有的kelvin找出并替换再将内容加到sb里
        while(result) {
            i++;
            m.appendReplacement(sb, "Kevin");
            System.out.println("第"+i+"次匹配后sb的内容是:"+sb);
            //继续查找下一个匹配对象
            result = m.find();
        }
        //最后调用appendTail()方法将最后一次匹配后的剩余字符串加到sb里;
        m.appendTail(sb);
        System.out.println("调用m.appendTail(sb)后sb的最终内容是:"+ sb.toString());
    }
}

最终输出结果为:
第1次匹配后sb的内容是:Kevin
第2次匹配后sb的内容是:Kevin Li and Kevin
第3次匹配后sb的内容是:Kevin Li and Kevin Chan are both working in Kevin
第4次匹配后sb的内容是:Kevin Li and Kevin Chan are both working in Kevin Chen’s Kevin
调用m.appendTail(sb)后sb的最终内容是:Kevin Li and Kevin Chan are both working in Kevin Chen’s KevinSoftShop company.

  • 3、group()/group(int group)/groupCount():
    该系列方法返回与组匹配的子串内容,下面代码将很好解释其用法:
import java.util.regex.*;

public class GroupTest{
    public static void main(String[] args) 
                         throws Exception {
        Pattern p = Pattern.compile("(ca)(t)");        
        Matcher m = p.matcher("one cat,two cats in the yard");
        StringBuffer sb = new StringBuffer();
        boolean result = m.find();
        System.out.println("该次查找获得匹配组的数量为:"+m.groupCount());
        for(int i=0;i<=m.groupCount();i++){
         System.out.println("第"+i+"组的子串内容为: "+m.group(i));
        }
    }
}

输出为:
该次查找获得匹配组的数量为:2
第1组的子串内容为:cat
第1组的子串内容为:ca
第2组的子串内容为:t

5、Java中String过滤数字、字母和中文

package com.lvb.regex;

/**
 * @Title:FilterStr.java
 * @Description:Java中过滤数字、字母和中文
 */
public class FilterStr {

	/**
	 *
	 * @Title : filterNumber
	 * @Type : FilterStr
	 * @Description : 过滤出数字
	 */
	public static String filterNumber(String number) {
		number = number.replaceAll("[^(0-9)]", "");
		return number;
	}

	/**
	 *
	 * @Title : filterAlphabet
	 * @Type : FilterStr
	 * @Description : 过滤出字母
	 */
	public static String filterAlphabet(String alph) {
		alph = alph.replaceAll("[^(A-Za-z)]", "");
		return alph;
	}

	/**
	 *
	 * @Title : filterChinese
	 * @Type : FilterStr
	 * @Description : 过滤出中文
	 */
	public static String filterChinese(String chin) {
		chin = chin.replaceAll("[^(\\u4e00-\\u9fa5)]", "");
		return chin;
	}

	/**
	 *
	 * @Title : filter
	 * @Type : FilterStr
	 * @Description : 过滤出字母、数字和中文
	 */
	public static String filter(String character) {
		character = character.replaceAll("[^(a-zA-Z0-9\\u4e00-\\u9fa5)]", "");
		return character;
	}

	/**
	 * @Title : main
	 * @Type : FilterStr
	 * @Description :
	 * @param args
	 */
	public static void main(String[] args) {
		/**
		 * 声明字符串you
		 */
		String you = "^&^&^you123$%$%你好";
		//调用过滤出数字的方法
		you = filterNumber(you);
		//打印结果
		System.out.println("过滤出数字:" + you);

		/**
		 * 声明字符串hai
		 */
		String hai = "¥%……4556ahihdjsadhj$%$%你好吗wewewe";
		//调用过滤出字母的方法
		hai = filterAlphabet(hai);
		//打印结果
		System.out.println("过滤出字母:" + hai);

		/**
		 * 声明字符串dong
		 */
		String dong = "$%$%$张三34584yuojk李四@#¥#%%¥……%&";
		//调用过滤出中文的方法
		dong = filterChinese(dong);
		//打印结果
		System.out.println("过滤出中文:" + dong);

		/**
		 * 声明字符串str
		 */
		String str = "$%$%$张三34584yuojk李四@#¥#%%¥……%&";
		//调用过滤出字母、数字和中文的方法
		str = filter(str);
		//打印结果
		System.out.println("过滤出字母、数字和中文:" + str);

	}

}

以上代码没有使用java.util.regex包,而是直接通过String类中与正则表达式相关的方法做处理。

6、Unicode编码完美的判断中文汉字和符号

[\\u4E00-\\u9FBF] 可以匹配中文汉字,但是不能匹配中文符号。我们可以根据Unicode编码完美的判断中文汉字和符号。

package com.lvb.regex;

import java.util.regex.Pattern;

public class CharUtil {

	public static void main(String[] args) {
		String[] strArr = new String[] { "www.micmiu.com", "!@#$%^&*()_+{}[]|\"'?/:;<>,.", "!¥……()——:;“”‘’《》,。?、",
				"不要啊", "やめて", "韩佳人", "???" };
		for (String str : strArr) {
			System.out.println("===========> 测试字符串:" + str);
			System.out.println("正则判断结果:" + isChineseByREG(str) + " -- " + isChineseByName(str));
			System.out.println("Unicode判断结果 :" + isChinese(str));
			System.out.println("详细判断列表:");
			char[] ch = str.toCharArray();
			for (int i = 0; i < ch.length; i++) {
				char c = ch[i];
				System.out.println(c + " --> " + (isChinese(c) ? "是" : "否"));
			}
		}
	}

	// 根据Unicode编码完美的判断中文汉字和符号
	private static boolean isChinese(char c) {
		Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
		if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
				|| ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
				|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
				|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
				|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
				|| ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
				|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
			return true;
		}
		return false;
	}

	// 完整的判断中文汉字和符号
	public static boolean isChinese(String strName) {
		char[] ch = strName.toCharArray();
		for (int i = 0; i < ch.length; i++) {
			char c = ch[i];
			if (isChinese(c)) {
				return true;
			}
		}
		return false;
	}

	// 只能判断部分CJK字符(CJK统一汉字)
	public static boolean isChineseByREG(String str) {
		if (str == null) {
			return false;
		}
		Pattern pattern = Pattern.compile("[\\u4E00-\\u9FBF]+");
		return pattern.matcher(str.trim()).find();
	}

	// 只能判断部分CJK字符(CJK统一汉字)
	public static boolean isChineseByName(String str) {
		if (str == null) {
			return false;
		}
		// 大小写不同:\\p 表示包含,\\P 表示不包含
		// \\p{Cn} 的意思为 Unicode 中未被定义字符的编码,\\P{Cn} 就表示 Unicode中已经被定义字符的编码
		String reg = "\\p{InCJK Unified Ideographs}";//&&\\P{Cn}";
		Pattern pattern = Pattern.compile(reg);
		return pattern.matcher(str.trim()).find();
	}
}

三、语法


这张语法表内容非常全,但是不太容易理解,很多东西不够详细,但是作为参考还是挺好用的。表来自于这里:Java正则表达式稍微做了些修改
正则表达式语法

字符说明
\将下一字符标记为特殊字符、文本、反向引用或八进制转义符。
^匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与"\n"或"\r"之后的位置匹配
$匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与"\n"或"\r"之前的位置匹配。
*零次或多次匹配前面的字符或子表达式。例如,zo* 匹配"z"和"zoo"。* 等效于 {0,}。
+一次或多次匹配前面的字符或子表达式。例如,"zo+"与"zo"和"zoo"匹配,但与"z"不匹配。+ 等效于 {1,}。
?零次或一次匹配前面的字符或子表达式。例如,"do(es)?“匹配"do"或"does"中的"do”。? 等效于 {0,1}。
{n}n 是非负整数。正好匹配 n 次。例如,"o{2}"与"Bob"中的"o"不匹配,但与"food"中的两个"o"匹配。
{n,}n 是非负整数。至少匹配 n 次。例如,"o{2,}“不匹配"Bob"中的"o”,而匹配"foooood"中的所有 o。"o{1,}“等效于"o+”。"o{0,}“等效于"o*”。
{n,m}M 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,"o{1,3}"匹配"fooooood"中的头三个 o。‘o{0,1}’ 等效于 ‘o?’。注意:您不能将空格插入逗号和数字之间。
?当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。例如,在字符串"oooo"中,"o+?“只匹配单个"o”,而"o+“匹配所有"o”。
.匹配除"\r\n"之外的任何单个字符。若要匹配包括"\r\n"在内的任意字符,请使用诸如"[\s\S]"之类的模式。
(pattern)匹配 pattern 并捕获该匹配的子表达式。可以使用 $0…$9 属性从结果"匹配"集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用"(“或者”)"。
(?:pattern)匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用"or"字符 ( | ) 组合模式部件的情况很有用。例如,‘industr(?:y|ies) 是比’industry|industries’ 更经济的表达式。
(?=pattern)执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,‘Windows (?=95|98|NT|2000)’ 匹配"Windows 2000"中的"Windows",但不匹配"Windows 3.1"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
(?!pattern)执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,‘Windows (?!95|98|NT|2000)’ 匹配"Windows 3.1"中的 “Windows”,但不匹配"Windows 2000"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
x|y匹配 x 或 y。例如,‘z|food’ 匹配"z"或"food"。’(z|f)ood’ 匹配"zood"或"food"。
[xyz]字符集。匹配包含的任一字符。例如,"[abc]“匹配"plain"中的"a”。
[^xyz]反向字符集。匹配未包含的任何字符。例如,"[^abc]“匹配"plain"中"p”,“l”,“i”,“n”。
[a-z]字符范围。匹配指定范围内的任何字符。例如,"[a-z]"匹配"a"到"z"范围内的任何小写字母。
[^a-z]反向范围字符。匹配不在指定的范围内的任何字符。例如,"[^a-z]"匹配任何不在"a"到"z"范围内的任何字符。
\b匹配一个字边界,即字与空格间的位置。例如,“er\b"匹配"never"中的"er”,但不匹配"verb"中的"er"。
\B非字边界匹配。“er\B"匹配"verb"中的"er”,但不匹配"never"中的"er"。
\cx匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是"c"字符本身。
\d数字字符匹配。等效于 [0-9]。
\D非数字字符匹配。等效于 [^0-9]。
\f换页符匹配。等效于 \x0c 和 \cL。
\n换行符匹配。等效于 \x0a 和 \cJ。
\r匹配一个回车符。等效于 \x0d 和 \cM。
\s匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。
\S匹配任何非空白字符。与 [^\f\n\r\t\v] 等效。
\t制表符匹配。与 \x09 和 \cI 等效。
\v垂直制表符匹配。与 \x0b 和 \cK 等效。
\w匹配任何字类字符,包括下划线。与"[A-Za-z0-9_]"等效。
\W与任何非单词字符匹配。与"[^A-Za-z0-9_]"等效。
\xn匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,"\x41"匹配"A"。"\x041"与"\x04"&"1"等效。允许在正则表达式中使用 ASCII 代码。
\num匹配 num,此处的 num 是一个正整数。到捕获匹配的反向引用。例如,"(.)\1"匹配两个连续的相同字符。
\n标识一个八进制转义码或反向引用。如果 \n 前面至少有 n 个捕获子表达式,那么 n 是反向引用。否则,如果 n 是八进制数 (0-7),那么 n 是八进制转义码。
\nm标识一个八进制转义码或反向引用。如果 \nm 前面至少有 nm 个捕获子表达式,那么 nm 是反向引用。如果 \nm 前面至少有 n 个捕获,则 n 是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 \nm 匹配八进制值 nm,其中 n 和 m 是八进制数字 (0-7)。
\nml当 n 是八进制数 (0-3),m 和 l 是八进制数 (0-7) 时,匹配八进制转义码 nml。
\un匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (©)。

匹配的模式(Pattern flags)

compile( )方法还有一个版本,它需要一个控制正则表达式的匹配行为的参数:

Pattern Pattern.compile(String regex, int flag)

flag的取值范围如下:

编译标志效果
Pattern.CANON_EQ当且仅当两个字符的"正规分解(canonical decomposition)“都完全相同的情况下,才认定匹配。比如用了这个标志之后,表达式"a/u030A"会匹配”?"。默认情况下,不考虑"规范相等性(canonical equivalence)"。
Pattern.CASE_INSENSITIVE (?i)默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。这个标志能让表达式忽略大小写进行匹配。要想对Unicode字符进行大小不明感的匹配,只要将UNICODE_CASE与这个标志合起来就行了。
Pattern.COMMENTS (?x)在这种模式下,匹配时会忽略(正则表达式里的)空格字符(注:不是指表达式里的"//s",而是指表达式里的空格,tab,回车之类)。注释从#开始,一直到这行结束。可以通过嵌入式的标志来启用Unix行模式。
Pattern.DOTALL(?s)在这种模式下,表达式’.‘可以匹配任意字符,包括表示一行的结束符。默认情况下,表达式’.'不匹配行的结束符。
Pattern.MULTILINE(?m)在这种模式下,’‘和’$‘分别匹配一行的开始和结束。此外,’‘仍然匹配字符串的开始,’$'也匹配字符串的结束。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。
Pattern.UNICODE_CASE(?u)在这个模式下,如果你还启用了CASE_INSENSITIVE标志,那么它会对Unicode字符进行大小写不明感的匹配。默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。
Pattern.UNIX_LINES(?d)在这个模式下,只有’\n’才被认作一行的中止,并且与’.’,’^’,以及’$'进行匹配。

在这些标志里面,Pattern.CASE_INSENSITIVEPattern.MULTILINE,以及Pattern.COMMENTS是最有用的(其中Pattern.COMMENTS还能帮我们把思路理清楚,并且/或者做文档)。注意,你可以用在表达式里插记号的方式来启用绝大多数的模式。这些记号就在上面那张表的各个标志的下面。你希望模式从哪里开始启动,就在哪里插记号。
可以用"OR" (’|’)运算符把这些标志合使用:
Pattern p = Pattern.compile("^java",Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);

四、参考

http://blog.csdn.net/allwefantasy/article/details/3136570

五、总结

本文大部分内容都是总结自这篇文章 JAVA 正则表达式 (超详细) ,我做了一些总结和整理,并添加了一些内容,使之更易读。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值