1033423 正则表达式

正则表达式

本文仅讨论Java语法的正则表达式。

  • 正则表达式
  • 语法
  • 常用正则表达式

正则表达式

正则表达式定义了字符串的模式。又称规则表达式

正则表达式可以用来搜索、编辑或处理文本。

正则表达式并不仅限于某一种语言,许多程序设计语言都支持利用正则表达式进行字符串操作,但是在每种语言中有细微的差别。这里只讨论Java语言的正则表达式用法。

java.util.regex包

常用的主要是以下三个类:

  1. 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))),有四个这样的组:

  • ((A)(B©))
  • (A)
  • (B©)
  • ©

可以通过调用 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*匹配zzoo*等效于{0,}
+ 一次或多次匹配前面的字符或子表达式。例如:zo+zozoo匹配,但与z不匹配。+等效于{1,}
? 零次或一次匹配前面的字符或子表达式。例如,do(es)?匹配dodoes?等效于{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中的plin
[a-z] 字符范围。匹配指定范围内的任何字符。例如,[a-z]匹配az范围内的任何小写字母。
[^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 制表符匹配。等效于\x09cl
\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匹配版权符号@

常用正则表达式

  1. 邮政编码:^\d{6}$
    • 网上大部分都是^[1-9]\d{5}$,这是不准确的,因为邮政编码是存在0开头的,比如呼和浩特
  • 邮箱:^[\w-]+@[\w-]+(\.[\w-]+)+$
  • 手机号码:^1[34578]\d{9}$
  • url:^(http|https|ftp)://([\w-]+\.)+[\w-]+(:\d+)?((/[\w-]+)+(.[\w-]+)?)?/?(\?([\w-]+=[\w-%]+)(&([\w-]+=[\w-%]+))*)?(#.*)*$
    • 第一部分,协议
    • 第二部分,如:www.baidu.com
    • 第三部分,端口
    • 第四部分,路径,路径可有可无,路径最后可能会以类似.html结尾。但如果没有路径则一定不会有类似结尾。路径的最后可能会以/结尾。
    • 第五部分,参数,第一个参数以?开始,后面的以&开始。参数可以没有,但只有一个参数的情况下,不可能以&开头,即如果有&开头的参数,则前面一定有?开头的参数。
    • 第六部分,网页位置指定标识符#,或称锚点
  • 18位身份证:^\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正则表达式的语法与示例




thanks! 顶部 底部 **
--郑泽旺
**
2017-12-26

你可能感兴趣的:(java基础,java,正则表达式)