用PHP实现正则表达式字符类减法

用PHP实现正则表达式字符类减法,php,regex,Php,Regex,嗨 我正在尝试匹配英国邮政编码,使用 我在PHP中使用它,但它与有效的邮政编码OL13 0EF不匹配。但是,当我删除-[CIKMOV]字符类减法时,此邮政编码确实匹配 我得到的印象是,我在PHP中做的字符类减法是错误的。如果有人能纠正我的错误,我将不胜感激 提前感谢你的帮助 Ross不支持字符类减法 因此,您可以枚举除CIKMOV之外的所有大写字母: ^[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9][ABDEFGHJLNPQRSTUWXYZ]{2}$ 可使用以下范围进行短路:

我正在尝试匹配英国邮政编码,使用

我在PHP中使用它,但它与有效的邮政编码OL13 0EF不匹配。但是,当我删除
-[CIKMOV]
字符类减法时,此邮政编码确实匹配

我得到的印象是,我在PHP中做的字符类减法是错误的。如果有人能纠正我的错误,我将不胜感激

提前感谢你的帮助


Ross不支持字符类减法

因此,您可以枚举除
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}$

我想你必须用
[ABD-HJLNP-UW-Z]
替换
[A-Z-[CIKMOV]]
。我认为php不支持字符类减法。我的替代方案是“A、B、D到H、J、L、N、P到U、W到Z”。

大多数正则表达式风格不支持字符类减法。相反,您可以使用前瞻性断言:

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

如果不支持类减法,您应该能够使用负类来实现减法

一些例子是
[^\D]=\D
[^[:^alpha:]=[a-zA-Z]

您的问题可以这样解决,在像
[^a-z[:^alpha:]CIKMOV]

[^

a-z#不是a-z

[:^alpha:][不是A-Za-z

CIKMOV#不是C、I、K、M、O、V

]

编辑-这也很有效,可能更容易阅读:
[^[:^alpha:][:lower:]CIKMOV]

[^

[:^alpha:][A-Za-z

[:lower:][不是a-z

CIKMOV#不是C、I、K、M、O、V

]

结果是一个字符类,它是a-Z,没有C、I、K、M、O、V
基本上是减法

下面是对两种不同的类混合物(Perl)的测试:

输出显示从测试的ascii字符0-255开始的A-Z减去CIKMOV的中断:
'AB DEFGH J L N PQRSTU WXYZ'


'AB DEFGH J L N PQRSTU WXYZ'

我真的不明白这是如何“更干净”。毫无疑问,这是一个更酷的解决方案,但比其他解决方案更神秘。这不是一个纯粹的字符类解决方案及其模糊性。从现在起一年后将{2}更改为{3},然后尝试调试它。你不会说。明天他们将改为数字邮政编码,你将不得不全部重写正则表达式!这需要ascii输入。@SilentGhost在perl中内部所有内容都是字节字符串,编码输出,解码输入。代码点和往常一样,否则就没有正则表达式。@Silent,是的,如果它不在预定类的范围内,并且没有减法类,那么就需要另一种选择。这正好在这个范围内,太棒了。它实现了与字符类减法相同的功能。
/^[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9](?!.?[CIKMOV])[A-Z]{2}$/
use strict;
use warnings;

my $match = '';

   # ANYOF[^\0-@CIKMOV[-\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[^\0-@CIKMOV[-\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";