用PHP实现正则表达式字符类减法
嗨 我正在尝试匹配英国邮政编码,使用 我在PHP中使用它,但它与有效的邮政编码OL13 0EF不匹配。但是,当我删除用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}$ 可使用以下范围进行短路:
-[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";