本文仅讨论Java语法的正则表达式。
正则表达式定义了字符串的模式。又称规则表达式
正则表达式可以用来搜索、编辑或处理文本。
正则表达式并不仅限于某一种语言,许多程序设计语言都支持利用正则表达式进行字符串操作,但是在每种语言中有细微的差别。这里只讨论Java语言的正则表达式用法。
常用的主要是以下三个类:
public final class Pattern
类
pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
public static Pattern compile(String regex)
public final class Matcher
类
Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
public Matcher matcher(CharSequence input)
public class PatternSyntaxException
类
PatternSyntaxException是一个非强制异常类(运行时异常),它表示一个正则表达式模式中的语法错误。
public class Demo {
public static void main(String[] args) {
System.out.println(isMobile("15388951793"));
System.out.println(isMobile("1153889517931"));
System.out.println(isMobile2("17621963326"));
System.out.println(isMobile2("1176219633261"));
System.out.println(isContainMobile("15388951793"));
System.out.println(isContainMobile("1176219633261"));
}
/**
* @param str
* @return
*/
private static boolean isMobile(String str){
String mobile = "^1[3|4|5|7|8][0-9]\\d{8}$";
return Pattern.matches(mobile, str);
}
/**
* 匹配
* @param str
* @return
*/
private static boolean isMobile2(String str){
String mobile = "^1[3|4|5|7|8][0-9]\\d{8}$";
Pattern pattern = Pattern.compile(mobile);
Matcher matcher = pattern.matcher(str);
return matcher.matches();
}
/**
* 检索
* @param str
* @return
*/
private static boolean isContainMobile(String str){
String mobile = "1[3|4|5|7|8][0-9]\\d{8}";
Pattern pattern = Pattern.compile(mobile);
Matcher matcher = pattern.matcher(str);
return matcher.find();
}
}
运行代码,输出:
true
false
true
false
true
true
注意find()与matches()方法的区别,即使去掉isMobile()方法中正则表达式的^和$,第二个和第四个结果依然是false。
捕获组是把多个字符当一个单独单元进行处理的方法,它通过对括号内的字符分组来创建。
捕获组是通过从左至右计算其开括号来编号。例如,在表达式((A)(B(C))),有四个这样的组:
可以通过调用 matcher 对象的 groupCount 方法来查看表达式有多少个分组。groupCount 方法返回一个 int 值,表示matcher对象当前有多个捕获组。
public class GroupDemo {
public static void main(String[] args) {
System.out.println(testGroup());
}
/**
* groupCount
* @return
*/
private static int testGroup(){
String str = "dsabcabc";
String patt = "(ds)(abc)(a(bc))";
Pattern pattern = Pattern.compile(patt);
Matcher matcher = pattern.matcher(str);
int count = matcher.groupCount();
if (matcher.find()) {
for (int i = 0; i <= count; i++) {
System.out.println(matcher.group(i));
}
} else {
System.out.println("没有匹配项");
}
return count;
}
}
运行代码,输出:
dsabcabc
ds
abc
abc
bc
4
注意:groupCount是4不是5。其中group(0)是总表达式,这算是一个特殊的组,该组不包括在 groupCount 的返回值中。
注:在Java字符串中,如要表示字符\
,需要用\\
。故下面出现的所有下划线在实际应用中都是一个\
对应到模式字符串中为两个\
,每一个\
前面一个\
都表示其后面的\
是字符\
,而不是转义该字符后面的字符。如\d
在正则表达式中匹配数字字符,则代码书写如下:
public static void main(String[] args) {
String regex = "\\d";
System.out.println(Pattern.matches(regex, "1"));//true
System.out.println(Pattern.matches(regex, "s"));//false
}
字符 | 说明 |
---|---|
\ | 将下一个字符标记为特殊字符、文本、反向引用或八进制转义符。 例如: n 匹配n ,\n 匹配换行符,\\n 匹配\n 。 |
^ | 匹配输入字符串开始的位置。如果设置了RegExp对象的Multiline属性,^ 还会与\n 或\r 之后的位置匹配。 |
$ | 匹配输入字符串结尾的位置。如果设置了RegExp对象的Multiline属性,$ 还会与\n 或\r 之前的位置匹配。 |
* | 零次或多次匹配前面的字符或子表达式。例如:zo* 匹配z 和zoo 。* 等效于{0,} 。 |
+ | 一次或多次匹配前面的字符或子表达式。例如:zo+ 与zo 和zoo 匹配,但与z 不匹配。+ 等效于{1,} 。 |
? | 零次或一次匹配前面的字符或子表达式。例如,do(es)? 匹配do 或does 。? 等效于{0,1} 。 |
{n} | n是非负整数,正好匹配n次。例如,o{2} 与Bob 中的o 不匹配,但与food 中的oo 匹配。 |
{n,} | n是非负整数,至少匹配n次。例如,o{2,} 不匹配Bob 中的0 ,而匹配fooood 中的所有的o。o{1,} 等效于o+ ,o{0,} 等效于o* 。 |
{n,m} | n和m是非负整数,其中n<=m。至少匹配n次,至多匹配m次。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] | 反向字符范围。匹配不在指定范围内的任何字符。 |
\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 和cl 。 |
\v | 垂直制表符匹配。等效于\x0b 和\cK 等效。 |
\w | 匹配任何单词字类字符,包括下划线。与[A-Za-z0-9_] 等效。 |
\W | 与任何非单词字类字符匹配。等效于[^A-Za-z0-9_] 。 |
\xn | 匹配n,此处的n是一个十六进制转义码。十六进制转义码必须正好是两位数长。 |
\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 匹配版权符号@ 。 |
^\d{6}$
^[1-9]\d{5}$
,这是不准确的,因为邮政编码是存在0开头的,比如呼和浩特^[\w-]+@[\w-]+(\.[\w-]+)+$
^1[34578]\d{9}$
^(http|https|ftp)://([\w-]+\.)+[\w-]+(:\d+)?((/[\w-]+)+(.[\w-]+)?)?/?(\?([\w-]+=[\w-%]+)(&([\w-]+=[\w-%]+))*)?(#.*)*$
^\d{6}(18|19|20)\d{2}(0\d|1[012])([012]\d|3[01])\d{3}(\d|x|X)$
public class Demo {
public static void main(String[] args) {
//邮箱
String regex = "^[\\w-]+@[\\w-]+(\\.[\\w-]+)+$";
commonMatch(regex, "[email protected]");//match
commonMatch(regex, "error@error");//not match
//手机
regex = "^1[34578]\\d{9}$";
commonMatch(regex, "15388951793");//match
commonMatch(regex, "77621963326");//not match
//url
regex = "^(http|https|ftp)://([\\w-]+\\.)+[\\w-]+(:\\d+)?((/[\\w-]+)+(.[\\w-]+)?)?/?(\\?([\\w-]+=[\\w-%]+)(&([\\w-]+=[\\w-%]+))*)?(#.*)*$";
commonMatch(regex, "http://127.0.0.1:51004/view/26");//match
commonMatch(regex, "http://www.baidu.com/.html");//not match
//身份证
regex = "^\\d{6}(18|19|20)\\d{2}(0\\d|1[012])([012]\\d|3[01])\\d{3}(\\d|x|X)$";
commonMatch(regex, "362331199310204611");//match
commonMatch(regex, "362331199313204611");//没有13月//not match
}
/**
* 完全匹配
* @param regex
* @param str
*/
private static void commonMatch(String regex, String str){
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
if (matcher.matches()) {
System.out.println( regex + ":" + str + ":match" );
} else {
System.out.println( regex + ":" + str + ":not match" );
}
}
}
再次强调:所有的正则表达式,在Java中书写时,一个/
都要用//
(两个)来替换。因为字符串解析的时候会自动将第一个解析为转义,那么该字符串传给Pattern对象的时候,该对象接收到的参数实际上还是一个/
。
在Java中,字符串"\\“表达的含义是\
。而字符串”"将被解释为转义字符。
Java正则表达式的语法与示例