正则表达式简介
概述
正则表达式定义了字符串的模式,可以用来搜索、编辑或处理文本。正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。Java的正则表达式和Perl的是最为相似的。
特点
正则表达式的特点是:
- 灵活性、逻辑性和功能性非常的强;
- 可以迅速地用极简单的方式达到字符串的复杂控制。
- 可读性比较差。
组成
Java正则表达式的类在 java.util.regex 包中,包括三个类:Pattern、Matcher 和 PatternSyntaxException。
- Pattern对象是正则表达式的已编译版本。他没有任何公共构造器,我们通过传递一个正则表达式参数给公共静态方法 compile 来创建一个pattern对象。
- Matcher是用来匹配输入字符串和创建的 pattern 对象的正则引擎对象。这个类没有任何公共构造器,我们用patten对象的matcher方法,使用输入字符串作为参数来获得一个Matcher对象。然后使用matches方法,通过返回的布尔值判断输入字符串是否与正则匹配。
- 如果正则表达式语法不正确将抛出PatternSyntaxException异常。
语法格式
-
- String regex = "(.*)(\\d+)(.*)";
-
- Pattern pattern = Pattern.compile(regex);
-
- Matcher matcher = pattern.matcher("This order was placed for QT3000! OK?");
- matcher.find();
Pattern标记
Pattern类的静态方法 :static Pattern compile(String regex, int flags)
将给定的正则表达式编译到具有给定标志的模式中。
其中的flags参数就是Pattern标记,这个标记在某些时候非常重要。
- Pattern.CANON_EQ: 启用规范等价。
- Pattern.CASE_INSENSITIVE: 启用不区分大小写的匹配。
- Pattern.COMMENTS: 模式中允许空白和注释。
- Pattern.DOTALL : 启用 dotall 模式。
- Pattern.LITERAL : 启用模式的字面值分析。
- Pattern.MULTILINE: 启用多行模式。
- Pattern.UNICODE_CASE: 启用 Unicode 感知的大小写折叠。
- Pattern.UNIX_LINES: 启用 Unix 行模式。
正则的功能:
字符串匹配
matches 和lookingAt 方法都用来尝试匹配一个输入序列模式。它们的不同是matcher要求整个序列都匹配,而lookingAt 不要求。这两个方法经常在输入字符串的开始使用。Matcher判断整个字符序列与模式是否匹配。当连续用Matcher对象检查多个字符串时候,可以使用Matcher.reset():重置匹配器,放弃其所有显式状态信息并将其添加位置设置为零。也可以使用Matcher.reset(CharSequence input) 重置此具有新输入序列的匹配器来重复使用匹配器。
-
- String telphone = "17612345678";
-
- String regex = "1[358][0-9]{9}";
-
- boolean flag = telphone.matches(regex);
- System.out.println(flag);
-
- String str = "heheeeeeeeeeee";
-
- String regex1 = "hehe+";
-
- boolean matches = str.matches(regex1);
- System.out.println(matches);
打印结果:
- public class RegexMatches {
- private static final String REGEX = "foo";
- private static final String INPUT = "fooooooooooooooooo";
- private static Pattern pattern;
- private static Matcher matcher;
-
- public static void main(String args[]) {
- pattern = Pattern.compile(REGEX);
- matcher = pattern.matcher(INPUT);
-
- System.out.println("Current REGEX is: " + REGEX);
- System.out.println("Current INPUT is: " + INPUT);
-
- System.out.println("lookingAt(): " + matcher.lookingAt());
- System.out.println("matches(): " + matcher.matches());
- }
- }
打印结果:
- Current REGEX is: foo
- Current INPUT is: fooooooooooooooooo
- lookingAt(): true
- matches(): false
字符串的切分
- String[] split(String regex)
根据给定的正则表达式的匹配来拆分此字符串。
- String[] split(String regex, int limit)
根据匹配给定的正则表达式来拆分此字符串。
当然,还有一个StringTokenizer类,可以用来切分字符串,但是现在SUN已经不推荐使用了。转变下思路,其实用正则表达式也可以达到将字符串切分为段的目的。
简单的:
- String str = "one:two:three:four:five";
-
- String[] split = str.split(":");
- for (String s : split) {
- System.out.println(s);
- }
打印结果:
较为复杂的:
-
-
- Pattern pattern = Pattern.compile("\\W");
- String[] words = pattern.split("one@two#three:four$five");
-
- for (String s : words) {
- System.out.println("Pattern.split : " + s);
- }
打印结果:
- Pattern.split : one
- Pattern.split : two
- Pattern.split : three
- Pattern.split : four
- Pattern.split : five
字符串的替换
- String.replace(char oldChar, char newChar)
返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 而生成的。
- String.replace(CharSequence target, CharSequence replacement)
使用指定的字面值替换序列替换此字符串匹配字面值目标序列的每个子字符串。
- String.replaceAll(String regex, String replacement)
使用给定的 replacement 字符串替换此字符串匹配给定的正则表达式的每个子字符串。
- String.replaceFirst(String regex, String replacement)
使用给定的 replacement 字符串替换此字符串匹配给定的正则表达式的第一个子字符串。
- StringBuffer.replace(int start, int end, String str)
使用给定 String 中的字符替换此序列的子字符串中的字符。
- StringBuilder.replace(int, int, java.lang.String)
使用给定 String 中的字符替换此序列的子字符串中的字符。
- Matcher.replaceAll(String replacement)
替换模式与给定替换字符串相匹配的输入序列的每个子序列。
- Matcher.replaceFirst(String replacement)
替换模式与给定替换字符串匹配的输入序列的第一个子序列。
简单的:
- String str = "one:two:three:four:five";
-
- String s1 = str.replace(":","000");
-
- String s2 = str.replaceAll(":", "000");
- System.out.println(s1);
- System.out.println(s2);
打印结果:
- one000two000three000four000five
- one000two000three000four000five
较复杂的:
-
- Pattern pattern = Pattern.compile("\\W");
- Matcher matcher = pattern.matcher("one@two#three:four$five");
-
- System.out.println(matcher.replaceFirst("000"));
-
- System.out.println(matcher.replaceAll("000"));
打印结果:
- one000two#three:four$five
- one000two000three000four000five
appendReplacement 和 appendTail 方法
Matcher 类也提供了appendReplacement 和appendTail 方法用于文本替换:
看下面的例子来解释这个功能:
- public class RegexMatches1
- {
- private static String REGEX = "a*b";
- private static String INPUT = "aabfooaabfooabfoob";
- private static String REPLACE = "-";
- public static void main(String[] args) {
- Pattern p = Pattern.compile(REGEX);
-
- Matcher m = p.matcher(INPUT);
- StringBuffer sb = new StringBuffer();
- while(m.find()){
-
- m.appendReplacement(sb,REPLACE);
- }
- m.appendTail(sb);
- System.out.println(sb.toString());
- }
- }
打印结果:
字符串捕获
捕获组是把多个字符当一个单独单元进行处理的方法,它通过对括号内的字符分组来创建。
例如,正则表达式(dog) 创建了单一分组,组里包含"d","o",和"g"。
捕获组是通过从左至右计算其开括号来编号。例如,在表达式((A)(B(C))),有四个这样的组:
- ((A)(B(C)))
- (A)
- (B(C))
- (C)
可以通过调用matcher对象的groupCount方法来查看表达式有多少个分组。groupCount方法返回一个int值,表示matcher对象当前有多个捕获组。
还有一个特殊的组(组0),它总是代表整个表达式。该组不包括在groupCount的返回值中。
-
- public class RegexMatches {
- public static void main(String args[]) {
-
-
- String line = "This order was placed for QT3000! OK?";
- String pattern = "(.*)(\\d+)(.*)";
-
-
- Pattern r = Pattern.compile(pattern);
-
-
- Matcher m = r.matcher(line);
- System.out.println(m.groupCount());
- if (m.find()) {
- System.out.println("Found value: " + m.group(0));
- System.out.println("Found value: " + m.group(1));
- System.out.println("Found value: " + m.group(2));
- } else {
- System.out.println("NO MATCH");
- }
- }
- }
- private static void test2() {
- String str = "aa1234bb7672cc";
-
-
- Pattern compile = Pattern.compile("aa(\\d+)bb([0-9]+)cc");
-
- Matcher matcher = compile.matcher(str);
-
- if(matcher.find()){
- String group = matcher.group();
- String group2 = matcher.group(0);
- String group3 = matcher.group(1);
- String group4 = matcher.group(2);
- System.out.println("group:"+group);
- System.out.println("group2:"+group2);
- System.out.println("group3:"+group3);
- System.out.println("group4:"+group4);
- }
- }
打印结果:
- group:aa1234bb7672cc
- group2:aa1234bb7672cc
- group3:1234
- group4:7672
综合示例:
- public class RegexExamples {
-
- public static void main(String[] args) {
-
- Pattern pattern = Pattern.compile("ab", Pattern.CASE_INSENSITIVE);
- Matcher matcher = pattern.matcher("ABcabdAb");
-
-
- while (matcher.find()) {
- System.out.println("Found the text \"" + matcher.group()
- + "\" starting at " + matcher.start()
- + " index and ending at index " + matcher.end());
- }
-
-
- pattern = Pattern.compile("\\W");
- String[] words = pattern.split("one@two#three:four$five");
- for (String s : words) {
- System.out.println("Split using Pattern.split(): " + s);
- }
-
-
-
- pattern = Pattern.compile("1*2");
- matcher = pattern.matcher("11234512678");
-
- System.out.println("Using replaceAll: " + matcher.replaceAll("_"));
-
- System.out.println("Using replaceFirst: " + matcher.replaceFirst("_"));
-
-
-
- System.out.println(Pattern.matches("(\\w\\d)\\1", "a2a2"));
- System.out.println(Pattern.matches("(\\w\\d)\\1", "a2b2"));
-
- System.out.println(Pattern.matches("(AB)(B\\d)\\2\\1", "ABB2B2AB"));
- System.out.println(Pattern.matches("(AB)(B\\d)\\2\\1", "ABB2B3AB"));
- }
-
- }
打印结果:
- Found the text "AB" starting at 0 index and ending at index 2
- Found the text "ab" starting at 3 index and ending at index 5
- Found the text "Ab" starting at 6 index and ending at index 8
- Split using Pattern.split(): one
- Split using Pattern.split(): two
- Split using Pattern.split(): three
- Split using Pattern.split(): four
- Split using Pattern.split(): five
- Using replaceAll: _345_678
- Using replaceFirst: _34512678
- true
- false
- true
- False
异常
PatternSyntaxException 类的方法
PatternSyntaxException 是一个非强制异常类,它指示一个正则表达式模式中的语法错误。
PatternSyntaxException 类提供了下面的方法来帮助我们查看发生了什么错误。
- public String getDescription()
获取错误的描述。
获取错误的索引。
- public String getPattern()
获取错误的正则表达式模式。
- public String getMessage()
返回多行字符串,包含语法错误及其索引的描述、错误的正则表达式模式和模式中错误索引的可视化指示。
正则表达式实例应用
1.验证用户名和密码:("^[a-zA-Z]\w{5,15}$")正确格式:"[A-Z][a-z]_[0-9]"组成,并且第一个字必须为字母6~16位;
2.验证电话号码:("^(\\d{3,4}-)\\d{7,8}$")正确格式:xxx/xxxx-xxxxxxx/xxxxxxxx;、
3.验证手机号码:"^1[3|4|5|7|8][0-9]\\d{8}$";
4.验证身份证号(15位或18位数字):"\\d{14}[[0-9],0-9xX]";
5.验证Email地址:("^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");
6.只能输入由数字和26个英文字母组成的字符串:("^[A-Za-z0-9]+$") ;
7.整数或者小数:^[0-9]+([.][0-9]+){0,1}$
8.只能输入数字:"^[0-9]*$"。
9.只能输入n位的数字:"^\d{n}$"。
10.只能输入至少n位的数字:"^\d{n,}$"。
11.只能输入m~n位的数字:"^\d{m,n}$"。
12.只能输入零和非零开头的数字:"^(0|[1-9][0-9]*)$"。
13.只能输入有两位小数的正实数:"^[0-9]+(.[0-9]{2})?$"。
14.只能输入有1~3位小数的正实数:"^[0-9]+(\.[0-9]{1,3})?$"。
15.只能输入非零的正整数:"^\+?[1-9][0-9]*$"。
16.只能输入非零的负整数:"^\-[1-9][0-9]*$"。
17.只能输入长度为3的字符:"^.{3}$"。
18.只能输入由26个英文字母组成的字符串:"^[A-Za-z]+$"。
19.只能输入由26个大写英文字母组成的字符串:"^[A-Z]+$"。
20.只能输入由26个小写英文字母组成的字符串:"^[a-z]+$"。
21.验证是否含有^%&',;=?$\"等字符:"[%&',;=?$\\^]+"。
22.只能输入汉字:"^[\u4e00-\u9fa5]{0,}$"。
23.验证URL:"^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$"。
24.验证一年的12个月:"^(0?[1-9]|1[0-2])$"正确格式为:"01"~"09"和"10"~"12"。
25.验证一个月的31天:"^((0?[1-9])|((1|2)[0-9])|30|31)$"正确格式为;"01"~"09"、"10"~"29"和“30”~“31”。
26.获取日期正则表达式:\\d{4}[年|\-|\.]\d{\1-\12}[月|\-|\.]\d{\1-\31}日?
评注:可用来匹配大多数年月日信息。
27.匹配双字节字符(包括汉字在内):[^\x00-\xff]
评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)
28.匹配空白行的正则表达式:\n\s*\r
评注:可以用来删除空白行
29.匹配HTML标记的正则表达式:<(\S*?)[^>]*>.*?</>|<.*? />
评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力
30.匹配首尾空白字符的正则表达式:^\s*|\s*$
评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式
31.匹配网址URL的正则表达式:[a-zA-z]+://[^\s]*
评注:网上流传的版本功能很有限,上面这个基本可以满足需求
32.匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
评注:表单验证时很实用
33.匹配腾讯QQ号:[1-9][0-9]{4,}
评注:腾讯QQ号从10 000 开始
34.匹配中国邮政编码:[1-9]\\d{5}(?!\d)
评注:中国邮政编码为6位数字
35.匹配ip地址:([1-9]{1,3}\.){3}[1-9]。
评注:提取ip地址时有用
36.匹配MAC地址:([A-Fa-f0-9]{2}\:){5}[A-Fa-f0-9]