JAVA中正則表達(dá)式使用介紹
一、什么是正則表達(dá)式
正則表達(dá)式是一種可以用于模式匹配和替換的強(qiáng)有力的工具。我們可以在幾乎所有的基于UNIX系統(tǒng)的工具中找到正則表達(dá)式的身影,例如,vi編輯器,Perl或PHP腳本語(yǔ)言,以及awk或sed shell程序等。此外,象JavaScript這種客戶端的腳本語(yǔ)言也提供了對(duì)正則表達(dá)式的支持。
正則表達(dá)式可以讓用戶通過(guò)使用一系列的特殊字符構(gòu)建匹配模式,進(jìn)行信息的驗(yàn)證。
此外,它還能夠高效地創(chuàng)建、比較和修改字符串,以及迅速地分析大量文本和數(shù)據(jù)以搜索、移除和替換文本。
例如:
二、基礎(chǔ)知識(shí)
1.1 開(kāi)始、結(jié)束符號(hào)(它們同時(shí)也屬于定位符)
我們先從簡(jiǎn)單的開(kāi)始。假設(shè)你要寫(xiě)一個(gè)正則表達(dá)式規(guī)則,你會(huì)用到 ^ 和 $ 符號(hào),他們分別是行首符、行尾符。
例如:/^\d+[0-9]?\d+$/
1.2 句點(diǎn)符號(hào)
假設(shè)你在玩英文拼字游戲,想要找出三個(gè)字母的單詞,而且這些單詞必須以“t”字母開(kāi)頭,以“n”字母結(jié)束。另外,假設(shè)有一本英文字典,你可以用正則表達(dá)式搜索它的全部?jī)?nèi)容。要構(gòu)造出這個(gè)正則表達(dá)式,你可以使用一個(gè)通配符——句點(diǎn)符號(hào)“.”。這樣,完整的表達(dá)式就是“t.n”,它匹配“tan”、“ten”、“tin”和“ton”,還匹配“t#n”、“tpn”甚至“t n”,還有其他許多無(wú)意義的組合。這是因?yàn)榫潼c(diǎn)符號(hào)匹配所有字符,包括空格、Tab字符甚至換行符:
1.3 方括號(hào)符號(hào)
為了解決句點(diǎn)符號(hào)匹配范圍過(guò)于廣泛這一問(wèn)題,你可以在方括號(hào)(“[]”)里面指定看來(lái)有意義的字符。此時(shí),只有方括號(hào)里面指定的字符才參與匹配。也就是說(shuō),正則表達(dá)式“t[aeio]n”只匹配“tan”、“Ten”、“tin”和“ton”。但“Toon”不匹配,因?yàn)樵诜嚼ㄌ?hào)之內(nèi)你只能匹配單個(gè)字符:
1.4 “或”符號(hào)
如果除了上面匹配的所有單詞之外,你還想要匹配“toon”,那么,你可以使用“|”操作符。“|”操作符的基本意義就是“或”運(yùn)算。要匹配“toon”,使用“t(a|e|i|o|oo)n”正則表達(dá)式。這里不能使用方擴(kuò)號(hào),因?yàn)榉嚼ㄌ?hào)只允許匹配單個(gè)字符;這里必須使用圓括號(hào)“()”。
1.5 表示匹配次數(shù)的符號(hào)
表一:顯示了表示匹配次數(shù)的符號(hào),這些符號(hào)用來(lái)確定緊靠該符號(hào)左邊的符號(hào)出現(xiàn)的次數(shù):
代碼/語(yǔ)法 |
說(shuō)明 |
* |
重復(fù)零次或更多次 |
+ |
重復(fù)一次或更多次 |
? |
重復(fù)零次或一次 |
{n} |
重復(fù)n次 |
{n,} |
重復(fù)n次或更多次 |
{n,m} |
重復(fù)n到m次 |
表二:常用符號(hào)
代碼/語(yǔ)法 |
相當(dāng)于 |
\w |
[0-9A-Za-z_] |
\W |
[^0-9A-Za-z_] |
\s |
[\t\n\r\f] |
\S |
[^\t\n\r\f] |
\d |
[0-9] |
\D |
[^0-9] |
表二中的符號(hào)意義:
· \w
包括下劃線的字母和數(shù)字。等同于[0-9A-Za-z_]
。
若為匹配多字節(jié)字符的正則表達(dá)式時(shí),則也會(huì)匹配日語(yǔ)的全角字符。
· \W
非字母和數(shù)字。\w
以外的單個(gè)字符。
· \s
空字符。相當(dāng)于[ \t\n\r\f]
· \S
非空字符。[ \t\n\r\f]
以外的單個(gè)字符。
· \d
數(shù)字。即[0-9]
· \D
非數(shù)字。\d以外的單個(gè)字符
1.6 定位符介紹(用于規(guī)定匹配模式在目標(biāo)對(duì)象中的出現(xiàn)位置)
較為常用的定位符包括: “^”, “$”, “\b” 以及 “\B”。其中,“^”定位符規(guī)定匹配模式必須出現(xiàn)在目標(biāo)字符串的開(kāi)頭,“$”定位符規(guī)定匹配模式必須出現(xiàn)在目標(biāo)對(duì)象的結(jié)尾,\b定位符規(guī)定匹配模式必須出現(xiàn)在目標(biāo)字符串的開(kāi)頭或結(jié)尾的兩個(gè)邊界之一,而“\B”定位符則規(guī)定匹配對(duì)象必須位于目標(biāo)字符串的開(kāi)頭和結(jié)尾兩個(gè)邊界之內(nèi),即匹配對(duì)象既不能作為目標(biāo)字符串的開(kāi)頭,也不能作為目標(biāo)字符串的結(jié)尾。同樣,我們也可以把“^”和“$”以及“\b”和“\B”看作是互為逆運(yùn)算的兩組定位符。舉例來(lái)說(shuō):
/^hell/
因?yàn)樯鲜稣齽t表達(dá)式中包含“^”定位符,所以可以與目標(biāo)對(duì)象中以 “hell”, “hello”或 “hellhound”開(kāi)頭的字符串相匹配。
/ar$/
因?yàn)樯鲜稣齽t表達(dá)式中包含“$”定位符,所以可以與目標(biāo)對(duì)象中以 “car”, “bar”或 “ar” 結(jié)尾的字符串相匹配。
/\bbom/
因?yàn)樯鲜稣齽t表達(dá)式模式以“\b”定位符開(kāi)頭,所以可以與目標(biāo)對(duì)象中以 “bomb”, 或 “bom”開(kāi)頭的字符串相匹配。
/man\b/
因?yàn)樯鲜稣齽t表達(dá)式模式以“\b”定位符結(jié)尾,所以可以與目標(biāo)對(duì)象中以 “human”, “woman”或 “man”結(jié)尾的字符串相匹配。
為了能夠方便用戶更加靈活的設(shè)定匹配模式,正則表達(dá)式允許使用者在匹配模式中指定某一個(gè)范圍而不局限于具體的字符。例如:
/[A-Z]/
上述正則表達(dá)式將會(huì)與從A到Z范圍內(nèi)任何一個(gè)大寫(xiě)字母相匹配。
/[a-z]/
上述正則表達(dá)式將會(huì)與從a到z范圍內(nèi)任何一個(gè)小寫(xiě)字母相匹配。
/[0-9]/
上述正則表達(dá)式將會(huì)與從0到9范圍內(nèi)任何一個(gè)數(shù)字相匹配。
/([a-z][A-Z][0-9])+/
上述正則表達(dá)式將會(huì)與任何由字母和數(shù)字組成的字符串,如 “aB0” 等相匹配。這里需要提醒用戶注意的一點(diǎn)就是可以在正則表達(dá)式中使用 “()” 把字符串組合在一起。“()”符號(hào)包含的內(nèi)容必須同時(shí)出現(xiàn)在目標(biāo)對(duì)象中。因此,上述正則表達(dá)式將無(wú)法與諸如 “abc”等的字符串匹配,因?yàn)?/span>“abc”中的最后一個(gè)字符為字母而非數(shù)字。
如果我們希望在正則表達(dá)式中實(shí)現(xiàn)類似編程邏輯中的“或”運(yùn)算,在多個(gè)不同的模式中任選一個(gè)進(jìn)行匹配的話,可以使用管道符 “|”。例如:
/to|too|2/
上述正則表達(dá)式將會(huì)與目標(biāo)對(duì)象中的 “to”, “too”, 或 “2” 相匹配。
正則表達(dá)式中還有一個(gè)較為常用的運(yùn)算符,即否定符 “[^]”。與我們前文所介紹的定位符 “^” 不同,否定符 “[^]”規(guī)定目標(biāo)對(duì)象中不能存在模式中所規(guī)定的字符串。例如:
/[^A-C]/
上述字符串將會(huì)與目標(biāo)對(duì)象中除A,B,和C之外的任何字符相匹配。一般來(lái)說(shuō),當(dāng)“^”出現(xiàn)在 “[]”內(nèi)時(shí)就被視做否定運(yùn)算符;而當(dāng)“^”位于“[]”之外,或沒(méi)有“[]”時(shí),則應(yīng)當(dāng)被視做定位符。
最后,當(dāng)用戶需要在正則表達(dá)式的模式中加入元字符,并查找其匹配對(duì)象時(shí),可以使用轉(zhuǎn)義符“\”。例如:
/Th\*/
上述正則表達(dá)式將會(huì)與目標(biāo)對(duì)象中的“Th*”而非“The”等相匹配。
三、正則表達(dá)式規(guī)則的例子
/^(\d{3}-|\d{4}-)?(\d{8}|\d{7})?$/ //國(guó)內(nèi)電話
/^[1-9]*[1-9][0-9]*$/ //騰訊QQ
/^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$/ //email地址
/^[a-zA-Z]+://(\\w+(-\\w+)*)(\\.(\\w+(-\\w+)*))*(\\?\\s*)?$/ //url
/^\d+$/ //非負(fù)整數(shù)
/^[0-9]*[1-9][0-9]*$/ //正整數(shù)
/^((-\\d+)|(0+))$/ //非正整數(shù)
/^-[0-9]*[1-9][0-9]*$/ //負(fù)整數(shù)
/^-?\\d+$/ //整數(shù)
/^\\d+(\\.\\d+)?$/ //非負(fù)浮點(diǎn)數(shù)
/^(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*))$/ //正浮點(diǎn)數(shù)
/^((-\\d+(\\.\\d+)?)|(0+(\\.0+)?))$/ //非正浮點(diǎn)數(shù)
/^(-(([0-9]+\\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/ //負(fù)浮點(diǎn)數(shù)
/^(-?\\d+)(\\.\\d+)?$/ //浮點(diǎn)數(shù)
/^[a-zA-Z]+$/ //由26個(gè)英文字母組成的字符串
/^[a-z]+$/ //由26個(gè)英文字母的大寫(xiě)組成的字符串
/^[a-z]+$/ //由26個(gè)英文字母的小寫(xiě)組成的字符串
/^[a-za-z0-9]+$/ //由數(shù)字和26個(gè)英文字母組成的字符串
/^\\w+$/ //由數(shù)字、26個(gè)英文字母或者下劃線組成的字符串
/^\d+[.]?\d+$/ //可以有小數(shù)點(diǎn)的任意多數(shù)字(全部為數(shù)字)
/(?=^[0-9a-zA-Z]{4,20}$)\w*[a-zA-Z]+\w*/ //同時(shí)滿足下面三個(gè)條件
(1) 數(shù)字和字母(2)4-20位(3)不能全部是數(shù)字
四、應(yīng)用
1.應(yīng)用于JavaScript (用來(lái)驗(yàn)證)
function doCheck(){
var patrn = /^\d+[.]?\d+$/;
var vf1 = document.queryForm.f2Text.value; //文本框
var vf2 = document.queryForm.f4Text.value;
var vf3 = document.queryForm.f6Text.value;
var va1 = document.queryForm.a2.checked; //單選按鈕
var va2 = document.queryForm.a4.checked;
var va3 = document.queryForm.a6.checked;
if(va1){
if(!patrn.exec(vf1)){
alert("請(qǐng)您輸入數(shù)字,如:30 、 5.8");
return;
}
}
if(va2){
if(!patrn.exec(vf2)){
alert("請(qǐng)您輸入數(shù)字,如:30 、 5.8");
return;
}
}
。。。 。。。
}
2.在Java中的應(yīng)用
Java包java.util.regex提供對(duì)正則表達(dá)式的支持。而且Java.lang.String類中的replaceAll和split函數(shù)也是調(diào)用的正則表達(dá)式來(lái)實(shí)現(xiàn)的。
正則表達(dá)式對(duì)字符串的操作主要包括:字符串匹配,指定字符串替換,指定字符串查找和字符串分割。下面就用一個(gè)例子來(lái)說(shuō)明這些操作是如何實(shí)現(xiàn)的:
<%@ page import="java.util.regex.*"%>;
<%
Pattern p=null; //正則表達(dá)式
Matcher m=null; //操作的字符串
boolean b;
String s=null;
StringBuffer sb=null;
int i=0;
//字符串匹配,這是不符合的
p = Pattern.compile("a*b");
m = p.matcher("baaaaab");
b = m.matches();
out.println(b+"<br>;");
//字符串匹配,這是符合的
p = Pattern.compile("a*b");
m = p.matcher("aaaaab");
b = m.matches();
out.println(b+"<br>;");
//字符串替換
p = Pattern.compile("ab");
m = p.matcher("aaaaab");
s = m.replaceAll("d");
out.println(s+"<br>;");
p = Pattern.compile("a*b");
m = p.matcher("aaaaab");
s = m.replaceAll("d");
out.println(s+"<br>;");
p = Pattern.compile("a*b");
m = p.matcher("caaaaab");
s = m.replaceAll("d");
out.println(s+"<br>;");
//字符串查找
p = Pattern.compile("cat");
m = p.matcher("one cat two cats in the yard");
sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "dog");
i++;
}
m.appendTail(sb);
out.println(sb.toString()+"<br>;");
out.println(i+"<br>;");
i=0;
p = Pattern.compile("cat");
m = p.matcher("one cat two ca tsi nthe yard");
sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "dog");
i++;
}
m.appendTail(sb);
out.println(sb.toString()+"<br>;");
out.println(i+"<br>;");
p = Pattern.compile("cat");
m = p.matcher("one cat two cats in the yard");
p=m.pattern();
m = p.matcher("bacatab");
b = m.matches();
out.println(b+"<br>;");
s = m.replaceAll("dog");
out.println(s+"<br>;");
i=0;
p = Pattern.compile("(fds){2,}");
m = p.matcher("dsa da fdsfds aaafdsafds aaf");
sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "dog");
i++;
}
m.appendTail(sb);
out.println(sb.toString()+"<br>;");
out.println(i+"<br>;");
p = Pattern.compile("cat");
m = p.matcher("one cat two cats in the yard");
sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, "<font color=\"red\">;cat</font>;");
}
m.appendTail(sb);
out.println(sb.toString()+"<br>;");
String aa=sb.toString();
out.println(aa+"<br>;");
//字符串分割
p = Pattern.compile("a+");
String[] a=p.split("caaaaaat");
for(i=0;i<a.length;i++)
{
out.println(a+"<br>;");
}
p = Pattern.compile("a+");
a=p.split("c aa aaaa t",0);
for(i=0;i<a.length;i++)
{
out.println(a+"<br>;");
}
p = Pattern.compile(" +");
a=p.split("c aa aaaa t",0);
for(i=0;i<a.length;i++)
{
out.println(a+"<br>;");
}
p = Pattern.compile("\\+");
a=p.split("dsafasdfdsafsda+dsagfasdfa+sdafds");
out.println(a.length+"<br>;");
for(i=0;i<a.length;i++)
{
out.println(a+"<br>;");
}