2014-02-21 3 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

К сожалению, Oracle поддерживает только узкую часть RegExp языка. Вы regexp не будут работать в 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 

This только тесты для IPv6. IPv4 не разрешен.

Поскольку аромат PL/SQL не имеет подпрограмм (?n), у нас нет выбора, кроме как развернуть все. И отсутствие негативного внешнего вида (?!pattern) заставляет нас имитировать его с помощью двух операций тестирования регулярных выражений.

\A и \z используются для согласования начала и конца строки, так как оба из них не зависят от флагов, а \z поведения будет таким же, как $ под D режимом в PCRE.

+1

красиво сделано! примечание: [a-f0-9] может быть заменено на [[: xdigit:]], что может быть более читаемым, если вы сойдете с ума по всем цифрам (и вы можете отказаться от переключателя i) –

+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% эквивалент оракула регулярных выражений, и я вижу, что используемые здесь слова, которые недоступны?> Возможно, вы можете разделить регулярное выражение между ipv4 и ipv6, чтобы избежать ограничения в oracle. И вобще REGEXP_LIKE (ф «ipv4pattern») или REGEXP_LIKE (ф «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 ** в течение пары недель и до сих пор не могу его найти. Вот моя первоначальная попытка найти одно: ** http: //stackoverflow.com/questions/21631669/regular-expression-regex-for-ipv6-separate-from-ipv4**. И вот мои последние тестовые примеры: ** http: //regex101.com/r/sV5cZ3**. Я все еще не нашел IPv6 только RegEx, который работает в PL/SQL, который работает для этих тестовых случаев. – 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') 

Modified из XML регулярного выражения в http://home.deds.nl/~aeron/regex/

Смежные вопросы