2011-01-24 2 views
4

HI,Regex Character Class Вычитание с PHP

Я пытаюсь соответствовать Великобритании почтовые индексы, используя шаблон из http://interim.cabinetoffice.gov.uk/media/291370/bs7666-v2-0-xsd-PostCodeType.htm,

/^[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9][A-Z-[CIKMOV]]{2}$/ 

Я использую это в PHP, но это не делает соответствует действительному почтовому индексу OL13 0EF. Однако этот почтовый индекс совпадает, если я удаляю вычитание класса символов .

У меня создалось впечатление, что я неправильно вычитаю класс символов в PHP. Я был бы очень признателен, если бы кто-то мог исправить мою ошибку.

Заранее за вашу помощь.

Росс

ответ

7

Большинство ароматизаторов регулярных выражений не поддерживают вычитание класса символов. Вместо того, чтобы вы могли использовать опережающее утверждение:

/^[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9](?!.?[CIKMOV])[A-Z]{2}$/ 
+0

+1 для более чистого подхода. – codaddict

+0

Я действительно не понимаю, как это «чище». Это более холодное решение, не сомневающееся, но более загадочное, чем другие решения. – fresskoma

+0

Это не чистое решение класса символов и его двусмысленность. Измените {2} на {3} год, а затем попробуйте отладить его. – sln

4

PCRE не поддерживает обугленный класс вычитания.

Таким образом, вы можете перечислить все прописные буквы, кроме CIKMOV:

^[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9][ABDEFGHJLNPQRSTUWXYZ]{2}$ 

, которые могут быть замкнуты с использованием диапазона, как:

^[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9][ABD-JLNP-UW-Z]{2}$ 
1

Я думаю, что вы будете иметь, чтобы заменить [A-Z-[CIKMOV]] с [ABD-HJLNP-UW-Z] , Я не думаю, что php поддерживает выражение класса символов. Моя альтернатива читает что-то вроде «A, B, D до H, J, L, N, P к U и W к Z».

5

Если класс Вычитание не поддерживается, вы должны быть в состоянии использовать отрицательные классы для достижения вычитаний.

Некоторые примеры [^\D] = \d, [^[:^alpha:]] = [a-zA-Z]

Ваша проблема может быть решена, как, что, используя негативный класс POSIX символов внутри класса символов, как [^a-z[:^alpha:]CIKMOV]

[^
a-z # not a-z
[:^alpha:] # not not A-Za-z
CIKMOV # not C,I,K,M,O,V
]

Редактировать - Это тоже работает и может быть легче читать: [^[:^alpha:][:lower:]CIKMOV]

[^
[:^alpha:] # A-Za-z
[:lower:] # not a-z
CIKMOV # not C,I,K,M,O,V
]

В результате класс символов, который AZ без C, I, K, M, O, V
в основном вычитание.

Вот тест 2 различных отваров класса (в Perl):

use strict; 
use warnings; 

my $match = ''; 

    # ANYOF[^\[email protected][-\377!utf8::IsAlpha] 
for (0 .. 255) { 
    if (chr($_) =~ /^[^a-z[:^alpha:]CIKMOV]$/) { 
     $match .= chr($_); next; 
    } 
    $match .= ' '; 
} 
$match =~ s/^ +//; 
$match =~ s/ +$//; 
print "'$match'\n"; 
$match = ''; 

    # ANYOF[^\[email protected][-\377+utf8::IsDigit !utf8::IsWord] 
for (0 .. 255) { 
    if (chr($_) =~ /^[^a-z\d\W_CIKMOV]$/) { 
     $match .= chr($_); next; 
    } 
    $match .= ' '; 
} 
$match =~ s/^ +//; 
$match =~ s/ +$//; 
print "'$match'\n"; 

Выход показывает прекращение в AZ минус CIKMOV, из протестированных символов ASCII 0-255:
'AB DEFGH J L N PQRSTU WXYZ'
'AB DEFGH J L N PQRSTU WXYZ'

+0

, для этого потребуется вход ascii. – SilentGhost

+0

@SilentGhost Внутренне в perl все это байтовая строка, кодируется, чтобы выйти, декодировать, чтобы войти. Codepoints, как обычно, не имеют никакого регулярного выражения. – sln

+0

@ Силлен, если он не находится в диапазоне заданных классов и нет класса вычитания, тогда нужна другая альтернатива. Это просто происходит в этом диапазоне. – sln