2014-02-21 80 views
2

我似乎無法找出此正則表達式在PL/SQL中不起作用的原因。IPv6正則表達式(RegEx)不能在PL/SQL中工作

if (REGEXP_LIKE(v,'/^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$/iD')) then 

這是用於驗證IPv4和IPv6,它來自這裏:https://stackoverflow.com/a/1934546/3112803

不知道這有什麼關係,但我也問了一下就完了D標誌這個問題:What Does This Regular Expression (RegEx) Flag Mean /iD

出於某種原因,這個正則表達式適用於我的測試在這個網站:http://regex101.com/PL/SQL一切都是無效的。

我的意思是由的是,有一些情況下,我覺得很失敗,但我一直在尋找了幾天,這是最好的一個我能找到的是在512個字符(512使用REGEXP_LIKE時的限制PL/SQL

我很感激任何幫助。謝謝!

這些是我使用的測試案例...

{1: Initial address, regex should say valid/match} 
select isValid('2001:0db8:0000:0000:0000:ff00:0042:8329','ipv6') from dual; 

{2: After removing all leading zeroes, regex should say valid/match} 
select isValid('2001:db8:0:0:0:ff00:42:8329','ipv6') from dual; 

{3: After omitting consecutive sections of zeroes, regex should say valid/match} 
select isValid('2001:db8::ff00:42:8329','ipv6') from dual; 

{4: The loopback address, regex should say valid/match} 
select isValid('0000:0000:0000:0000:0000:0000:0000:0001','ipv6') from dual; 

{5: The loopback address be abbreviated to ::1 by using both rules, regex should say valid/match} 
select isValid('::1','ipv6') from dual; 

{6: This should be valid/match} 
select isValid('ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:192.168.158.190','ipv6') from dual; 

{7: This should be valid/match} 
select isValid('::','ipv6') from dual; 

{8: IPv6 applications to communicate directly with IPv4 applications, regex should say valid/match} 
select isValid('0:0:0:0:0:ffff:192.1.56.10','ipv6') from dual; 

{9: should NOT be valid/match} 
select isValid('::ffff:192.1.56.10/96','ipv6') from dual; 

{old formats used for tunneling, these should NOT be valid/matches} 
{10} 
select isValid('0:0:0:0:0:0:192.1.56.10','ipv6') from dual; 
{11} 
select isValid('::192.1.56.10/96','ipv6') from dual; 

{These 4 should be valid/match} 
{12} 
select isValid('::FFFF:129.144.52.38','ipv6') from dual; 
{13} 
select isValid('::129.144.52.38','ipv6') from dual; 
{14} 
select isValid('::FFFF:d','ipv6') from dual; 
{15} 
select isValid('1080:0:0:0:8:800:200C:417A','ipv6') from dual; 

{These 4 should NOT be valid/match} 
{16} 
select isValid('::FFFF:d.d.d','ipv6') from dual; 
{17} 
select isValid('::FFFF:d.d','ipv6') from dual; 
{18} 
select isValid('::d.d.d','ipv6') from dual; 
{19} 
select isValid('::d.d','ipv6') from dual; 

有人告訴我,試驗#6錯了,ABCD:ABCD:ABCD:ABCD:ABCD:ABCD:192.168.158.190是不是一個有效的IPv6地址,是正確的?

測試用例8-11來自這裏:http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzai2%2Frzai2ipv6addrformat.htm但我被告知10 & 11已不再使用。

+1

從XML正則表達式改性不幸的是,Oracle支持僅正則表達式語言的狹窄部分。您的正則表達式在Oracle中不起作用。 –

+0

第二次,測試用例6無效。 10和11也不是。 –

+0

是的,我知道。它也在下面提到。我會更新這個問題,以免混淆。這個被接受的答案是迄今爲止我發現的最好答案。然而@nhahtdh不同意你關於項目#6的格式。 – gfrobenius

回答

5

代替在一個單一的正則表達式做的一切,這是更好地打破正則表達式分成較小的並對其進行測試:

if (
    /* IPv6 expanded */ 
    REGEX_LIKE(v, '\A[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7}\z', 'i') 
    /* IPv6 shorthand */ 
    OR (NOT REGEX_LIKE(v, '\A(.*?[a-f0-9](:|\z)){8}', 'i') 
     AND REGEX_LIKE(v, '\A([a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,6})?::([a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,6})?\z', 'i')) 
    /* IPv6 dotted-quad notation, expanded */ 
    OR REGEX_LIKE(v, '\A[a-f0-9]{1,4}(:[a-f0-9]{1,4}){5}:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}\z', 'i') 
    /* IPv6 dotted-quad notation, shorthand */ 
    OR (NOT REGEX_LIKE(v, '\A(.*?[a-f0-9]:){6}', 'i') 
     AND REGEX_LIKE(v, '\A([a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,4})?::([a-f0-9]{1,4}:){0,5}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}\z', 'i')) 
    ) then 

這只是測試使用IPv6。 IPv4是不允許的。

由於PL/SQL風格沒有子程序調用(?n),所以除了將所有東西都展開外,別無選擇。而缺乏負面預測(?!pattern)迫使我們用2個正則表達式測試操作來模擬它。

\A\z用於匹配開頭和字符串的結尾,因爲他們都不受標誌和\z行爲是下PCRE D模式一樣$

+1

很好地完成! 注意:[a-f0-9]可以用[[:xdigit:]]替代,如果你瘋了所有的數字,那麼可讀性更強(你可以省略掉我的開關) –

+0

這太棒了!這是迄今爲止最接近的答案,我一直在尋找很長時間。我將測試用例添加到原始問題中。你的模式說6號是匹配的,但我被告知這不是一個有效的IPv6地址?它也在測試9和11上失敗。但我不確定那些是否是有效的格式。我有另一個帖子非常類似於這個同樣的事情,但也爲ColdFusion(如果你想要那裏點):http://stackoverflow.com/questions/21631669/regular-expression-regex-for-ipv6-與ipv4分開謝謝! – gfrobenius

+1

@gfrobenius:我不確定爲什麼6不是有效的IPv6。格式方面,它不應該是錯的。測試9和11用於IPv6地址**前綴**,不是IPv6地址。 – nhahtdh

3

你必須從頭開始清除/ iD,這是perl語法的一部分,表明它是一個正則表達式。

末我切換意味着忽略大小寫,並可以作爲你的REGEXP_LIKE的一個額外的參數,所以:

if (REGEXP_LIKE(v,'^(?>(?>([a-f0-9]{1,4})(?>:(?1)){7}|(?!(?:.*[a-f0-9](?>:|$)){8,})((?1)(?>:(?1)){0,6})?::(?2)?)|(?>(?>(?1)(?>:(?1)){5}:|(?!(?:.*[a-f0-9]:){6,})(?3)?::(?>((?1)(?>:(?1)){0,4}):)?)?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?4)){3}))$','i')) the 

還有更多的問題,因爲Perl的正則表達式是不等價的100%到Oracle正則表達式,我看到這裏使用的patter不可用,如?> 也許你可以分開ipv4和ipv6之間的正則表達式,以避免在oracle中達到極限。而只是做REGEXP_LIKE(IP, 'ipv4pattern')或REGEXP_LIKE(IP, 'ipv6pattern')

調整上述正則表達式的東西,在甲骨文工作的IPv4部分給我:

REGEXP_LIKE(ip,'^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])$','i') 
+0

啊,謝謝,我忘了標誌需要在REGEXP_LIKE()調用中用逗號分隔。不幸的是,它仍然沒有幫助。所有的測試都會失效。我認爲@EgorSkriptunoff可能是對的。 – gfrobenius

+0

我編輯了我的帖子,在oracle中爲ipv4部分包含了一個工作正則表達式。 –

+0

是的,我已經有一個單獨的IPv4工作,但謝謝,我會比較你的我的。是的,我希望他們分開。但是我一直在努力尋找** IPv6 only **解決方案几個星期,但仍然找不到。這是我最初嘗試找到一個:** http://stackoverflow.com/questions/21631669/regular-expression-regex-for-ipv6-separate-from-ipv4**。這裏是我最近的測試用例:** http://regex101.com/r/sV5cZ3**。我仍然沒有找到適用於這些測試用例的適用於'PL/SQL'的IPv6唯一正則表達式。 – gfrobenius

1
REGEXP_LIKE(ip,'^(([\dA-F]{1,4}:([\dA-F]{1,4}:([\dA-F]{1,4}:([\dA-F]{1,4}:([\dA-F]{1,4}:[\dA-F]{0,4}|:[\dA-F]{1,4})?|(:[\dA-F]{1,4}){0,2})|(:[\dA-F]{1,4}){0,3})|(:[\dA-F]{1,4}){0,4})|:(:[\dA-F]{1,4}){0,5})((:[\dA-F]{1,4}){2}|:(25[0-5]|(2[0-4]|1\d|[1-9])?\d)(\.(25[0-5]|(2[0-4]|1\d|[1-9])?\d)){3})|(([\dA-F]{1,4}:){1,6}|:):[\dA-F]{0,4}|([\dA-F]{1,4}:){7}:)\z', 'i') 

http://home.deds.nl/~aeron/regex/