JAVA 正则表达式
A:在代码中使用正则表达式的三种写法:
其中Pattern类和Match类使用的时候,需要
import java.util.regex.Pattern;
写法一:
public static void printPattern1()
{
String str="123";
String regex="[\\d]{3}";
//初始化Pattern正则表达式类
Pattern pattern = Pattern.compile(regex);
//初始化Matcher匹配类
Matcher m = pattern.matcher(str);
m.matches();// 得到匹配结果true或者false
System.out.println(m.matches());
}
写法二:
public static void printPattern2()
{
String str="123";
String regex="[\\d]{3}";
System.out.println(Pattern.matches(regex, str));
}
写法三:
直接利用String中的Match进行比较
public static void printPattern3()
{
String str="123";
String regex="[\\d]{3}";
System.out.println(str.matches(regex));
}
B 正则表达式验证规则解析说明(java中的)
首先要声明一点的是:
^ 匹配的是一个字符,而不是整个字符串。比如^Java至少要匹配J字母一次,然后后面的a,v,a这些是紧挨着进行输出的。因为字符串是由单个字符组成的,所以不可能允许去匹配整个串的
关于[abc] 这种匹配的说明,这种表示的意思是匹配a或者b或者c,只能匹配其中的一个字符。
[a-z]
在匹配a到z这中间所有的小写字母时候为以上写法
上面的[a-z]就等价于
[abcdefghijklmnopqrstuvwxyz]
针对上面的我们可以abcd的匹配,我们可以将条件改为[a-d]
[a-z]中间的-这个显然是一种很好的做法,如果我们要匹配的一些字符太多。那挨个写出来的话,会不会感觉到很崩溃。
同理匹配[A-Z] 为26个大写字母
那么问题来了,我这里面要匹配所有的英文大小写字母咋办那?
有的小伙伴可能会说我可以这样啊
[a-z][A-Z] 很聪明,的确这是一种做法。
不过还有这种[a-zA-Z] 这种实际上就是[a-z][A-Z]的缩写形式
别问我为什么会这样写。自己摸索吧
好了我们要匹配0-9这10个任意字符应该怎么写那?
[0-9]
同理我们模仿以上的写法,可以自由组合出:
总结一下[]这种的用法:
[a-z] 等价于[abcdefghijklmnopqrstuvwxyz]
[a-zA-Z] 等价于[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVwXYZ]
等价于[a-z[A-Z]]这种写法,等价于[a-zA-Z];
有的小伙伴可能会说了[]里面的- 这么强大,那么我想用[a-zA-Z],我可以直接
用[A-z]表示吗?来试一下
备注:
因为A的ASCI码为65,而小a的ASCI码为97,所以A-z的ASCI码会包含所有的
a-z 和A-Z之间的所有范围。来让我们实践一下
以下结果说明什么了,是可以的。
有的小伙伴或者脑洞打开,会想到,如果我把条件写成这样,会得到什么
[z-a];
小伙伴们被惊呆了吧。别怕。由此我们想到这是人家由小到大的规定
好了,有的小伙伴可能会说了,以上是固定的a-Z或者A-Z,而我想要在匹配条件中
要加入自己定义的_或者—或者.咋办那?
看完这个例子,是不是瞬晕了,那么多- - ,别急,我们分析一下:
[a-z-A-Z] 表示的是匹配a-Z或者A-Z或者-
你也可以这样写:[a-zA-Z-]
接下来我们看一下这种情况:
[^abc] 这种表示的是匹配非a ,非b,非c那,还是匹配的是非a,b或者c那?
有的小伙伴会说第二种吗?有的说当然是第一种,瞬间都快打起来了。别急,遇到
问题,写一遍,就得到答案了。
[]中加入^后加再次限制条件「[^]」
[^a-z] 条件限制在非小写a to z范围中一个字符
[^A-Z] 条件限制在非大写A to Z范围中一个字符
[^a-zA-Z] 条件限制在非小写a to z或非大写A to Z范围中一个字符
[^0-9] 条件限制在非小写0 to 9范围中一个字符
[^0-9a-z] 条件限制在非小写0 to 9或非a to z范围中一个字符
[^0-9[a-z]] 条件限制在非小写0 to 9或非a to z范围中一个字符(交集
//取a-z中除掉s和 v的字符。用^的话咋实现那?
貌似没有什么好的方法。
针对以上的情况,为了省事,有些写法还有如下表达式
接着我们来看验证正则规则2
好多啊,会不会吓坏了,别怕,其实很简单。
[abc]这种的啥都不写的,默认验证一次,其中可以为a或b或者c
实际上也就相当于
[abc]==[abc]{1}==[abc]{1,1}
[abc]?匹配0次或者1次,其中0次默认为””的这种形式,而不是其他的除去
a,b,c的这三个字符。
[abc]?匹配的是abc这个整体那,还是a或者b或者c这个单个字符那,单个字符
匹配一次或者多次的话[abc]+这种
因为+表示的是1次或者多次,如果是0次的话,则为false。
其实在匹配”ab” 的时候,因为[abc]里面可以任意匹配a或者b,所以先第一次匹配a
表示成功,又因为[abc]+后面有这个+所以会又可以再次追加任意多个字符进行匹配,第二次匹配字符b,b属于[abc]中的范畴,所以匹配成。
[abc]*这种,匹配 0次,1次,或者多次
总结:
X* 如果X为[abc]的话则会匹配abc中的其中的一个元素进行大于等于0次的匹配
如果将X改为abc*这种形式那,则只会匹配abccccc 这种形式的,是针对字符c进行0次或者多次匹配
如果要将abc做为整体匹配,想要输入abcabc正确,abccb这种错误的那
此时就必须要见万能的() 括号了,做为一个整体,进行匹配。(abc)*
以上代码为:
小练习:
《1》
String str2="[a-z]*";
System.out.println("".matches(str2));
结果:true;
分析:实际上就是匹配a到z中的字符0次或以上
《2》
String str3="\\d?[a-z]*";
System.out.println("123abc".matches(str3));
结果:false
分析:
\d?只能匹配0次或者1次,所以只能匹配到1
后面的2和3不在[a-z]范围之后,所以会为false
如果改为这种则正确:
String str3="\\d*[a-z]*";
System.out.println("123abc".matches(str3));
结果:true
String str3="\\d+[a-z]*";
System.out.println("123abc".matches(str3));
结果:true
《3》记住转义字符为\. 而不是/ 在输出+字符时候时候必须为 //+
String str4="(/+86|0086)?\\b{2}";
System.out.println("+8612".matches(str4));
结果:
如这种:
[a-z]+[0-2]{1,2}
此处的+相当于[a-z]+输出一次或者多次。如果要想输出a+12 这种形式的话,就必须使用转义\\+了
//注释块的时候Ctrl+Shit+/ 去掉块注释的时候Ctrl+Shit+\
因为正则表达式中要表示\\这种形式就需要首先给每个进行转型
m.matches 不会吐出
理解 Java 正则表达式怪异的 \\ 和 \\\\,让您见怪不怪
2010-11-29 — Unmi
Java 语言里的几大变革,一为 jdk1.4 引入的正则表达式,jdk1.5 引入的泛型。没有泛型之前有不少人曾想方设法从编译器入手让 Java 支持泛型。说到泛型 Perl 无疑是该方面的佼佼者,虽然我们不要求 Java 的正则表式能像 Perl 那样可以用来写诗,但至少能有 JavaScript 好用些,可是还不如。JavaScript 里 // 两斜线一框就是一个模式,分组和后向引用更方便,当然前面那两家伙是动态的,不太好比。
复杂的用法不说,且说 Java 的正则表达式在匹配点(.) 和斜杠(\),表达式要分别写作 \\. 和 \\\\, 难看些,不好理解。幸好还有些人记住了,匹配点(.) 或 {、[、(、?、$、^ 和 * 这些特殊符号要要前加双斜框,匹配 \ 时要用四斜杠,这确实能让你包走天涯的。那么为什么是这样呢,不是一个斜杠、三个或更多呢,所以知其然还要知其所以然,这样才能每次心中有数,方能以一变 应万变。
首先,Java 的正则表达式语法说明参见:http://download.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html。
用 最简单的例子来说明问题吧,不创建 Pattern、Matcher 等对象,就看 String 对象的 replaceAll(String regex, String replacement),它第一个参数接收的就是一个正则表达式,我们可以在 IDE 里的调试器中看 "a.b".replaceAll(".","") 能不能得到你期望的结果。
先说为什么像点号(其他的特殊符号还有引号中的 "{、[、(、?、$、^ 和 *")前面要加双斜杠,注意逗号(,) 不是这一类特殊字符,因为它只会出现在中括号或花括号中。
显然,如果直接执行
1 |
|
得到的值不是你想要的结果,成空字符串了,因为点号 "." 匹配了所有的字符,那要只匹配点号该如何呢,对的,双斜杠
1 |
|
那为什么是双斜杠呢?这个很简单,因为点号(.),是个特殊字符,所以它前面需要需要加个斜杠给它转义,你要真只用一个斜杠来转义,问题就来了,提示你:
Invalid escape sequence (valid ones are \b \t \n \f \r \" \' \\),也就是 Java 不认 \. 序列,所以还需要前面再加一道杠给其后的斜杠转义出一个斜杠给点号(.) 用,也就是在 Java 字符串看起来是 “\\.”, 但作为正则表达式来说就是 “\.”,这于其语言的正则表达式是一致的。
也 就是说 Java 的正则表达式字符串有两层次的意义,那就是 Java 字符串转义出符合正则表达式语法的字符串,“\\.”, 转义后交给正则表达式的就是 “\.”,这是符合传统的。因为我们平时字符串转义后直接用于输出,所以带来不少误解,这里的最终的正则表达式就是 Java 字符串的输出。
细心的同志一定能看到在调试器里的显示,看我们写成的“\\.”, 在调试器里显示的是 “\\\\.”,说的是如果我们要得到 “\\.”,这样的输出那 Java 的字符串就必须写成 “\\\\.”, 两个斜杠转义出一个斜杠。
好 的,理解了上面的由来,我们来看看用四个斜杠来匹配一个斜杠的原理。主要原因是斜杠 \ 本身就是用于转义别的字符的,当然它的架子不是一般的大。因为正则表达式串就是 Java 字符串的输出,正常思维在正则表达式里匹配斜杠用 “\\”, 那么在 Java 程序里向控制台输出 “\\”双斜杠该如何写呢,对了,就是 “\\\\”,就这么简单。
再一次从错误里找下原因吧,假如我们写成:
1 |
|
报什么错呢?String literal is not properly closed by a double-quote,因为斜杠把其后的双引号给转义了,当然字符串是未结束。再给它加个斜杠又如何呢?
1 |
|
Java 的语法是通过了,但是执行正则表达式不干了,你转义出来的交给正则表达式的一个斜杠,叫它情何以堪,该去转义谁呢?所以运行时异常报 An exception occurred: java.util.regex.PatternSyntaxException。
如果写成三个斜杠呢?
1 |
|
所以这样推来推去也是该写成
1 |
|
对于正则表达式看到的就是 “\\”,哪种语言的正则表达式要的也是这个,也是第一个斜杠转义了第二个,第三个转义了第四个,最终就是 “\\”,正则表达式里转互相转义一下就是 “\”了。
我原来理解还只是停留下转义啊,再转义的基础上,随着写这篇才更加理解到其中要义的,才发现,原来 Java 的正则表达式和其他语言的正则表达式语言是统一的。只要记住一点,你要想的正则表达式字符串是什么,而正则表达式字符串就是 Java 字符串的的输出结果,你就知道应该怎么写了。
最后来看下 Eclipse 调试器里仅匹配单个斜杠时,IDE 里显示的有多疯狂:
这让你体验到四个斜杠又何其多也。注:全文中的斜框标准意义上应该叫做反斜杠,在此就不作全文替换了。