需求:
匹配手機(jī)號(hào),第一位可以是+,可以沒有+,后面的全部要是數(shù)字,如:
+861359415665
8613659558555
1356856455
都是合法的。
+aa156945555
aa1359556666
aaddssdfdfsd
都是不合法的。
正則:
- SQL> SELECT * FROM DUAL WHERE regexp_like('+333333' ,'^[\+]*[[:digit:]]+'); --該+轉(zhuǎn)義或者不轉(zhuǎn)義,結(jié)果是一樣的
-
- DUMMY
- -----
- X
[sql]
- SQL> SELECT * FROM DUAL WHERE regexp_like('aa333333' ,'^[+]*[[:digit:]]+');
-
- DUMMY
- -----
解釋:
1.^代表開始,*表示出現(xiàn)0次或多次,+表示出現(xiàn)1次或多次,[:digit:]代表0-9的純數(shù)字(還有$代表以什么結(jié)尾,如果是[[:digit:]]+$代表以數(shù)字結(jié)尾)。該正則的意思就是:
以+0次或多次開頭,緊接著后面數(shù)字出現(xiàn)一次或多次(即一定要有數(shù)字)。
2.dual表中,永遠(yuǎn)只有1行記錄。查詢出dual中有記錄,證明where條件成立,反之不成立。
先前寫了一個(gè)錯(cuò)誤的正則:
注意,就只少了一個(gè)代表開始符號(hào)的^。少了這個(gè)符號(hào),說明這個(gè)正則的意思是:
+出現(xiàn)0次或多次(即+可以出現(xiàn),可以不出現(xiàn)!!),緊后面的數(shù)字出現(xiàn)1次或多次。前面已經(jīng)+可以出現(xiàn)0次了,證明沒有+也可以,那么就是只要字符串中有數(shù)字(+aa111a,aass11111……),這個(gè)正則恒成立,錯(cuò)誤深重啊!!
Oracle正則表達(dá)式的應(yīng)用by 溫州--名次
在oracle里正則表達(dá)式有四個(gè)函數(shù)可用,分別是regexp_like、regexp_substr、regexp_instr 和regexp_replace。這里在我們oracle 10g里靈活應(yīng)用。
先來簡(jiǎn)單介紹一下正則表達(dá)式的內(nèi)容,正則表達(dá)式是做為快速查詢的文本內(nèi)容的,在linux應(yīng)用比較多,首先,行的起始與結(jié)束 “^”這個(gè)字符是表示只查找行首的內(nèi)容。“$”這個(gè)字符只查找行末的內(nèi)容。接下來是“^”還可以做為一個(gè)排除字符來使用。還是使用例子來做一個(gè)演示比較明了一下。
這里我使用regexp_like這個(gè)函數(shù)來做,這樣可以我們平時(shí)會(huì)使用的比較多。
select * from test_table
where regexp_like(field_1,'^1234')
這個(gè)就是表示是以1234打頭的字符串是不是有匹配的。這里和like的方式是一樣的。
select * from test_table
where regexp_like(field_1,'^[12]234')
這里多了一個(gè)[]這里做一個(gè)獨(dú)立字符,這里表示是以1或2開始,并且接著是234這個(gè)里的字符就會(huì)是匹配的。
select * from test_table
where regexp_like(field_1,'^(歐陽(yáng)|李)小二')
這里我們就可以表達(dá),這個(gè)查詢一個(gè)姓是歐陽(yáng)或李的,名字叫小二的字符串。這里多了一個(gè)()這個(gè)是做一個(gè)為字符串的方式來寫的與[]剛好是對(duì)應(yīng)。
這里還有一個(gè)“|”來表示或的意思。
select * from test_table
where regexp_like(field_1,'^李[小]*二')
這里我們就可以查詢李小二或是李二,再或者是李小小二,都可以,這里我們需要講一下是[]后面帶了一個(gè)*,這個(gè)是表示0~無窮大 字符去匹配。這個(gè)[]我們還可以添加一個(gè)“+”來表示1~無窮大的字符去匹配,也可以更加精準(zhǔn)一些,在[]后面{1,3}這里就是表示1個(gè)到3個(gè)相同字符的匹配。還有一個(gè)“?”來說表示1或是0個(gè)。
select * from test_table
where regexp_like(field_1,'李[^小]二')
這里我們可以查詢到姓李的,但是第二字不是“小”這個(gè)字。
select * from test_table
where regexp_like(field_1,'[0-9]')
這里是表示我們查詢字符串含有0-9的數(shù)字的字符串。
select * from test_table
where regexp_like(field_1,'[a-z]')
這里是表示我們查詢字符串含有a-z的小寫字母的字符串。
select * from test_table
where regexp_like(field_1,'[A-z]')
這里是表示我們查詢字符串含有A-z的所有字母的字符串。
select * from test_table
where regexp_like(name,'[[:alpha:]]')
這里是表示查詢匹配任意字母,也包括中文字
select * from test_table
where regexp_like(name,'[[:alnum:]]')
這里是表示查詢匹配任意字母和數(shù)字
select * from test_table
where regexp_like(name,'[[:digit:]]')
這里是表示查詢匹配任意數(shù)字
Select * from test_table
Where regexp_like(name,’of’,’i’)
這里就是of不區(qū)分大小寫
Select * from test_table
Where regexp_like(name,’^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$’)
這樣我們可以查詢是不是ip格式
接下來介紹一下regexp_substr
這個(gè)也是一個(gè)非常實(shí)用的一個(gè)函數(shù)
REGEXP_SUBSTR與SUBSTR函數(shù)相同,返回截取的子字符串
REGEXP_SUBSTR(srcstr, pattern [, position [, occurrence [, match_option]]])
注:
srcstr 源字符串
pattern 正則表達(dá)式樣式
position 開始匹配字符位置
occurrence 匹配出現(xiàn)次數(shù)
match_option 匹配選項(xiàng)(區(qū)分大小寫)
SELECT regexp_substr('1PSN/231_3253/ABc', '[[:alnum:]]+') FROM dual;
Output: 1PSN
[[:alnum:]]+ 表示匹配1個(gè)或者多個(gè)字母或數(shù)字字符
SELECT regexp_substr('1PSN/231_3253/ABc', '[[:alnum:]]+', 1, 2) FROM dual;
Output: 231
與上面一個(gè)例子相比,多了兩個(gè)參數(shù)
1 表示從源字符串的第一個(gè)字符開始查找匹配
2 表示第2次匹配到的字符串(默認(rèn)值是“1”,如上例)
select regexp_substr('@@/231_3253/ABc','@*[[:alnum:]]+') from dual;
Output: 231
@* 表示匹配0個(gè)或者多個(gè)@
[[:alnum:]]+ 表示匹配1個(gè)或者多個(gè)字母或數(shù)字字符
注意:需要區(qū)別“+”和“*”的區(qū)別
select regexp_substr('1@/231_3253/ABc','@+[[:alnum:]]*') from dual;
Output: @
@+ 表示匹配1個(gè)或者多個(gè)@
[[:alnum:]]* 表示匹配0個(gè)或者多個(gè)字母或數(shù)字字符
select regexp_substr('1@/231_3253/ABc','@+[[:alnum:]]+') from dual;
Output: Null
@+ 表示匹配1個(gè)或者多個(gè)@
[[:alnum:]]+ 表示匹配1個(gè)或者多個(gè)字母或數(shù)字字符
select regexp_substr('@1PSN/231_3253/ABc125','[[:digit:]]+$') from dual;
Output: 125
[[:digit:]]+$ 表示匹配1個(gè)或者多個(gè)數(shù)字結(jié)尾的字符
select regexp_substr('1@/231_3253/ABc','@+[[:alnum:]]+') from dual;
Output: Null
@+ 表示匹配1個(gè)或者多個(gè)@
[[:alnum:]]+ 表示匹配1個(gè)或者多個(gè)字母或數(shù)字字符
select regexp_substr('@1PSN/231_3253/ABc125','[[:digit:]]+$') from dual;
Output: 125
[[:digit:]]+$ 表示匹配1個(gè)或者多個(gè)數(shù)字結(jié)尾的字符
select regexp_substr('@1PSN/231_3253/ABc','[^[:digit:]]+$') from dual;
Output: /ABc
[^[:digit:]]+$ 表示匹配1個(gè)或者多個(gè)不是數(shù)字結(jié)尾的字符
select regexp_substr('Tom_Kyte@oracle.com','[^@]+') from dual;
Output: Tom_Kyte
[^@]+ 表示匹配1個(gè)或者多個(gè)不是“@”的字符
select regexp_substr('1PSN/231_3253/ABc','[[:alnum:]]*',1,2)
from dual;
Output: Null
[[:alnum:]]* 表示匹配0個(gè)或者多個(gè)字母或者數(shù)字字符
注:因?yàn)槭瞧ヅ?個(gè)或者多個(gè),所以這里第2次匹配的是“/”(匹配了0次),而不是“231”,所以結(jié)果是“Null”
這里我們有時(shí)候會(huì)查詢字符串里asdfafd<main>dafda 這里我們要取出<main>這個(gè)字符串
Select regexp_substr('asdfafd<main>dafda','<[^>]+>') from dual
Output: <main>
這里我們?cè)?lt;>中間去一個(gè)^>這樣在匹配<之后,在向后查詢的時(shí)候確保在匹配到>之前不再在有>,不然的話就要有可以出錯(cuò)的情況。
Select regexp_substr('asdfafd<main>da>fda','<[^<]+>') from dual
Output: <main>da>
在這個(gè)例子中,我們?cè)?lt;main>之后還在da>,這樣的話,如果我們沒有添加^>,正則表達(dá)式就會(huì)向后繼續(xù)去匹配,直到最后一個(gè)>為至,這樣就會(huì)出現(xiàn)偏差
這個(gè)通常用來實(shí)現(xiàn)字符串的列傳行
select regexp_substr('123;234;345;456;567;678;789','[^;]+',1,rownum) from dual
connect by rownum <= length('123;234;345;456;567;678;789') - length(replace('123;234;345;456;567;678;789',';'))+1
這里length這里操作是先得到有多少個(gè)“;”,再通過 connect by rownum方式來做一行成多行的操作,在變成多行之后,可以通過regexp_substr來取字符串的操作
接著上一個(gè)例子
a,b,c,d,e,d,f,a,n這樣的一個(gè)字符串,我們現(xiàn)在要把字符串里一些重復(fù)去掉,這樣的話結(jié)果是a,b,c,d,e,f,n去掉了d與a的兩個(gè)字符串
select wm_concat(new_row) from (
select distinct regexp_substr('a,b,c,d,e,d,f,a,n','[^,]+',1,rownum) new_row from dual
connect by rownum<=length('a,b,c,d,e,d,f,a,n')-length(replace('a,b,c,d,e,d,f,a,n',',')))
通過轉(zhuǎn)成多行的,再用distinct 去掉重復(fù),然后我們?cè)偻ㄟ^wm_concat來字符串合并來完成。
再來一個(gè)ip格式轉(zhuǎn)換的例子吧,我們一般的IP的格式是12.19.168.27現(xiàn)在要不足3位的補(bǔ)足前面為0,結(jié)果是012.019.168.027
select wm_concat(new_value) from (
select
lpad(regexp_substr('12.19.168.27','[^.]+',1,rownum) ,3,'0') new_value,rownum
from dual
connect by rownum<5
order by rownum)
來一個(gè)驗(yàn)證IP是數(shù)字是否正確
select count(*) from(
select
lpad(regexp_substr('12.19.168.27','[^.]+',1,rownum) ,3,'0') new_value,rownum
from dual
connect by rownum<5)
where new_value>=0 and new_value<256
having count(*) =4
來一個(gè)IP字符串格式轉(zhuǎn)換成數(shù)字型IP
select sum(new_value*power(256,4-rm)) from (
select regexp_substr('12.19.168.27','[^.]+',1,rownum) new_value,rownum rm from dual
connect by rownum<=4
)
接下來介紹一個(gè)regexp_instr函數(shù)
REGEXP_INSTR 函數(shù)使用正則表達(dá)式返回搜索模式的起點(diǎn)和終點(diǎn)。REGEXP_INSTR 的語(yǔ)法如下所示。REGEXP_INSTR 返回一個(gè)整數(shù),指出搜索模式的開始或結(jié)束的位置,如果沒有發(fā)現(xiàn)匹配的值,則返回0。
語(yǔ)法:
2.REGEXP_INSTR與INSTR函數(shù)相同,返回字符串位置
REGEXP_INSTR(srcstr, pattern [, position [, occurrence [, return_option [,match_option]]]])
與REGEXP_SUBSTR一樣,它也有變量pattern、position(開始位置)、occurrence 和match_parameter;這里主要介紹一下新參數(shù)return_option 的作用,它允許用戶告訴Oracle,模式出現(xiàn)的時(shí)候,要返回什么內(nèi)容。
Select regexp_instr('asdfafd<main>da>fda','sd') from dual
Output:2
這里去查詢sd的位置,這個(gè)和instr是在相同的
Select regexp_instr('asdfafd<main>da>fda','da',1,2) from dual
這里是查詢da第二出現(xiàn)的位置
還有我們經(jīng)常會(huì)遇到一種情況是,查詢某個(gè)字段,如果是等于“上海”或“北京”或者我們溫州就寫成大城市,其它的寫成小城市,我們一般會(huì)考慮使用decode這種方式
Select decode('上海','上海','大城市','北京' ,'大城市' ,'溫州' ,'大城市','小城市') from dual
只有兩個(gè)我們可能覺的sql也不是很冗長(zhǎng),如果有四五個(gè)的話,就有點(diǎn)長(zhǎng)了,這里使用regexp_instr就可以很多的去操作
Select decode (regexp_instr('北京','^(上海|北京|溫州)'),0,'小城市', '大城市') from dual
通過regexp_instr不匹配時(shí)為0的條件,這樣就可以完成了
最后一個(gè)函數(shù)regexp_replace
REGEXP_REPLACE 函數(shù)是用另外一個(gè)值來替代串中的某個(gè)值。例如,可以用一個(gè)匹配數(shù)字來替代字母的每一次出現(xiàn)。REGEXP_REPLACE的格式如下所示
語(yǔ)法:
4.REGEXP_REPLACE與REPLACE函數(shù)相同,替換原字符串中的字符內(nèi)容
REGEXP_REPLACE(srcstr, pattern [,replacestr [, position [, occurrence [,match_option]]]])
這個(gè)替換函數(shù)還是一個(gè)非常好用的。
如我們?cè)谟幸粋€(gè)字符串a(chǎn)dfadfa (main) next 現(xiàn)在我們要把()替換成<>,這里我們可能想用replace就可以搞定了,但是我們現(xiàn)在做的是(之后必須有)這樣的()我們才替換把<>.
select regexp_replace('adfadfa (main) next ','(\()([^\)]*)(\))','<\2>') from dual
output: adfadfa <main> next
這里還是一個(gè)\做為轉(zhuǎn)義字符。
再來一個(gè)ip格式轉(zhuǎn)換的例子吧,我們一般的IP的格式是12.19.168.27現(xiàn)在要不足3位的補(bǔ)足前面為0,結(jié)果是012.019.168.027
select regexp_replace(
regexp_replace('12.19.168.27','([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})',
'00\1.00\2.00\3.00\4') ,
'([0-9]*)([0-9]{3}\.)([0-9]*)([0-9]{3}\.)([0-9]*)([0-9]{3}\.)([0-9]*)([0-9]{3}$)','\2\4\6\8')
from dual
output: 012.019.168.027
這里我分成兩步來操作,regexp_replace('12.19.168.27','([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3}).([0-9]{1,3})',
'00\1.00\2.00\3.00\4')我首先讓每個(gè)小字符串做添加0,這樣每個(gè)字符串都會(huì)大于3,再
'([0-9]*)([0-9]{3}\.)([0-9]*)([0-9]{3}\.)([0-9]*)([0-9]{3}\.)([0-9]*)([0-9]{3}$)','\2\4\6\8')
這整個(gè)字符串分成8段,這樣我們只要2、4、6、8這四個(gè)段就可以了。
下面一個(gè)例子中,在每?jī)蓚€(gè)字符之間插入一個(gè)空格符
SELECT regexp_replace('YAHOO', '(.)', '\1 ') AS output FROM dual;
Output: Y A H O O
這個(gè)用一個(gè)循環(huán)的方式去操作,還蠻好的。
select regexp_replace(
regexp_replace('12.19.168.27','([^.]+)'
,'00\1')
,'([^.]*)([^.]{3})','\2')
from dual
接著剛才那個(gè),我們可以把replace循環(huán)替換的方式來操作。