需求:
匹配手機號,第一位可以是+,可以沒有+,後面的全部要是數字,如:
+861359415665
8613659558555
1356856455
都是合法的。
+aa156945555
aa1359556666
aaddssdfdfsd
都是不合法的。
正則:
SQL> SELECT * FROM DUAL WHERE regexp_like('+333333' ,'^[\+]*[[:digit:]]+'); --該+轉義或者不轉義,結果是一樣的DUMMY-----X
SQL> SELECT * FROM DUAL WHERE regexp_like('aa333333' ,'^[+]*[[:digit:]]+');DUMMY-----
解釋:
1.^代表開始,*表示出現0次或多次,+表示出現1次或多次,[:digit:]代表0-9的純數字(還有$代表以什麼結尾,如果是[[:digit:]]+$代表以數字結尾)。該正則的意思就是:
以+0次或多次開頭,緊接著後面數字出現一次或多次(即一定要有數字)。
2.dual表中,永遠只有1行記錄。查詢出dual中有記錄,證明where條件成立,反之不成立。
先前寫了一個錯誤的正則:
[\+]*[[:digit:]]+
注意,就只少了一個代表開始符號的^。少了這個符號,說明這個正則的意思是:
+出現0次或多次(即+可以出現,可以不出現!!),緊後面的數字出現1次或多次。前面已經+可以出現0次了,證明沒有+也可以,那麼就是只要字串中有數字(+aa111a,aass11111……),這個正則恒成立,錯誤深重啊!!
OracleRegex的應用by 溫州--名次
在oracle裡Regex有四個函數可用,分別是regexp_like、regexp_substr、regexp_instr 和regexp_replace。這裡在我們oracle 10g裡靈活應用。
先來簡單介紹一下Regex的內容,Regex是做為快速查詢的常值內容的,在linux應用比較多,首先,行的起始與結束 “^”這個字元是表示只尋找行首的內容。“$”這個字元只尋找行末的內容。接下來是“^”還可以做為一個排除字元來使用。還是使用例子來做一個示範比較明了一下。
這裡我使用regexp_like這個函數來做,這樣可以我們平時會使用的比較多。
select * from test_table
where regexp_like(field_1,'^1234')
這個就是表示是以1234打頭的字串是不是有匹配的。這裡和like的方式是一樣的。
select * from test_table
where regexp_like(field_1,'^[12]234')
這裡多了一個[]這裡做一個獨立字元,這裡表示是以1或2開始,並且接著是234這個裡的字元就會是匹配的。
select * from test_table
where regexp_like(field_1,'^(歐陽|李)小二')
這裡我們就可以表達,這個查詢一個姓是歐陽或李的,名字叫小二的字串。這裡多了一個()這個是做一個為字串的方式來寫的與[]剛好是對應。
這裡還有一個“|”來表示或的意思。
select * from test_table
where regexp_like(field_1,'^李[小]*二')
這裡我們就可以查詢李小二或是李二,再或者是李小小二,都可以,這裡我們需要講一下是[]後面帶了一個*,這個是表示0~無窮大 字元去匹配。這個[]我們還可以添加一個“+”來表示1~無窮大的字元去匹配,也可以更加精準一些,在[]後面{1,3}這裡就是表示1個到3個相同字元的匹配。還有一個“?”來說表示1或是0個。
select * from test_table
where regexp_like(field_1,'李[^小]二')
這裡我們可以查詢到姓李的,但是第二字不是“小”這個字。
select * from test_table
where regexp_like(field_1,'[0-9]')
這裡是表示我們查詢字串含有0-9的數位字串。
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:]]')
這裡是表示查詢匹配任意字母和數字
select * from test_table
where regexp_like(name,'[[:digit:]]')
這裡是表示查詢匹配任一數字
Select * from test_table
Where regexp_like(name,’of’,’i’)
這裡就是of不區分大小寫
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
這個也是一個非常實用的一個函數
REGEXP_SUBSTR與SUBSTR函數相同,返回截取的子字串
REGEXP_SUBSTR(srcstr, pattern [, position [, occurrence [, match_option]]])
註:
srcstr 源字串
pattern Regex樣式
position 開始匹配字元位置
occurrence 匹配出現次數
match_option 匹配選項(區分大小寫)
SELECT regexp_substr('1PSN/231_3253/ABc', '[[:alnum:]]+') FROM dual;
Output: 1PSN
[[:alnum:]]+ 表示匹配1個或者多個字母或數字字元
SELECT regexp_substr('1PSN/231_3253/ABc', '[[:alnum:]]+', 1, 2) FROM dual;
Output: 231
與上面一個例子相比,多了兩個參數
1 表示從源字串的第一個字元開始尋找匹配
2 表示第2次匹配到的字串(預設值是“1”,如上例)
select regexp_substr('@@/231_3253/ABc','@*[[:alnum:]]+') from dual;
Output: 231
@* 表示匹配0個或者多個@
[[:alnum:]]+ 表示匹配1個或者多個字母或數字字元
注意:需要區別“+”和“*”的區別
select regexp_substr('1@/231_3253/ABc','@+[[:alnum:]]*') from dual;
Output: @
@+ 表示匹配1個或者多個@
[[:alnum:]]* 表示匹配0個或者多個字母或數字字元
select regexp_substr('1@/231_3253/ABc','@+[[:alnum:]]+') from dual;
Output: Null
@+ 表示匹配1個或者多個@
[[:alnum:]]+ 表示匹配1個或者多個字母或數字字元
select regexp_substr('@1PSN/231_3253/ABc125','[[:digit:]]+$') from dual;
Output: 125
[[:digit:]]+$ 表示匹配1個或者多個數字結尾的字元
select regexp_substr('1@/231_3253/ABc','@+[[:alnum:]]+') from dual;
Output: Null
@+ 表示匹配1個或者多個@
[[:alnum:]]+ 表示匹配1個或者多個字母或數字字元
select regexp_substr('@1PSN/231_3253/ABc125','[[:digit:]]+$') from dual;
Output: 125
[[:digit:]]+$ 表示匹配1個或者多個數字結尾的字元
select regexp_substr('@1PSN/231_3253/ABc','[^[:digit:]]+$') from dual;
Output: /ABc
[^[:digit:]]+$ 表示匹配1個或者多個不是數字結尾的字元
select regexp_substr('Tom_Kyte@oracle.com','[^@]+') from dual;
Output: Tom_Kyte
[^@]+ 表示匹配1個或者多個不是“@”的字元
select regexp_substr('1PSN/231_3253/ABc','[[:alnum:]]*',1,2)
from dual;
Output: Null
[[:alnum:]]* 表示匹配0個或者多個字母或者數字字元
註:因為是匹配0個或者多個,所以這裡第2次匹配的是“/”(匹配了0次),而不是“231”,所以結果是“Null”
這裡我們有時候會查詢字串裡asdfafd<main>dafda 這裡我們要取出<main>這個字串
Select regexp_substr('asdfafd<main>dafda','<[^>]+>') from dual
Output: <main>
這裡我們在<>中間去一個^>這樣在匹配<之後,在向後查詢的時候確保在匹配到>之前不再在有>,不然的話就要有可以出錯的情況。
Select regexp_substr('asdfafd<main>da>fda','<[^<]+>') from dual
Output: <main>da>
在這個例子中,我們在<main>之後還在da>,這樣的話,如果我們沒有添加^>,Regex就會向後繼續去匹配,直到最後一個>為至,這樣就會出現偏差
這個通常用來實現字串的列傳行
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這裡操作是先得到有多少個“;”,再通過 connect by rownum方式來做一行成多行的操作,在變成多行之後,可以通過regexp_substr來取字串的操作
接著上一個例子
a,b,c,d,e,d,f,a,n這樣的一個字串,我們現在要把字串裡一些重複去掉,這樣的話結果是a,b,c,d,e,f,n去掉了d與a的兩個字串
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',',')))
通過轉成多行的,再用distinct 去掉重複,然後我們再通過wm_concat來字串合并來完成。
再來一個ip格式轉換的例子吧,我們一般的IP的格式是12.19.168.27現在要不足3位的補足前面為0,結果是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)
來一個驗證IP是數字是否正確
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
來一個IP字串格式轉換成數字型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
)
接下來介紹一個regexp_instr函數
REGEXP_INSTR 函數使用Regex返回搜尋模式的起點和終點。REGEXP_INSTR 的文法如下所示。REGEXP_INSTR 返回一個整數,指出搜尋模式的開始或結束的位置,如果沒有發現匹配的值,則返回0。
文法:
2.REGEXP_INSTR與INSTR函數相同,返回字串位置
REGEXP_INSTR(srcstr, pattern [, position [, occurrence [, return_option [,match_option]]]])
與REGEXP_SUBSTR一樣,它也有變數pattern、position(開始位置)、occurrence 和match_parameter;這裡主要介紹一下新參數return_option 的作用,它允許使用者告訴Oracle,模式出現的時候,要返回什麼內容。
Select regexp_instr('asdfafd<main>da>fda','sd') from dual
Output:2
這裡去查詢sd的位置,這個和instr是在相同的
Select regexp_instr('asdfafd<main>da>fda','da',1,2) from dual
這裡是查詢da第二出現的位置
還有我們經常會遇到一種情況是,查詢某個欄位,如果是等於“上海”或“北京”或者我們溫州就寫成大城市,其它的寫成小城市,我們一般會考慮使用decode這種方式
Select decode('上海','上海','大城市','北京' ,'大城市' ,'溫州' ,'大城市','小城市') from dual
只有兩個我們可能覺的sql也不是很冗長,如果有四五個的話,就有點長了,這裡使用regexp_instr就可以很多的去操作
Select decode (regexp_instr('北京','^(上海|北京|溫州)'),0,'小城市', '大城市') from dual
通過regexp_instr不匹配時為0的條件,這樣就可以完成了
最後一個函數regexp_replace
REGEXP_REPLACE 函數是用另外一個值來替代串中的某個值。例如,可以用一個匹配數字來替代字母的每一次出現。REGEXP_REPLACE的格式如下所示
文法:
4.REGEXP_REPLACE與REPLACE函數相同,替換原字串中的字元內容
REGEXP_REPLACE(srcstr, pattern [,replacestr [, position [, occurrence [,match_option]]]])
這個替換函數還是一個非常好用的。
如我們在有一個字串adfadfa (main) next 現在我們要把()替換成<>,這裡我們可能想用replace就可以搞定了,但是我們現在做的是(之後必須有)這樣的()我們才替換把<>.
select regexp_replace('adfadfa (main) next ','(\()([^\)]*)(\))','<\2>') from dual
output: adfadfa <main> next
這裡還是一個\做為逸出字元。
再來一個ip格式轉換的例子吧,我們一般的IP的格式是12.19.168.27現在要不足3位的補足前面為0,結果是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')我首先讓每個小字串做添加0,這樣每個字串都會大於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')
這整個字串分成8段,這樣我們只要2、4、6、8這四個段就可以了。
下面一個例子中,在每兩個字元之間插入一個空格符
SELECT regexp_replace('YAHOO', '(.)', '\1 ') AS output FROM dual;
Output: Y A H O O
這個用一個迴圈的方式去操作,還蠻好的。
select regexp_replace(
regexp_replace('12.19.168.27','([^.]+)'
,'00\1')
,'([^.]*)([^.]{3})','\2')
from dual
接著剛才那個,我們可以把replace迴圈替換的方式來操作。
2010-7-5
轉載自:溫州--名次