Perl正则及grep中括号字符类取反使用问题咨询
问题解答
1. 为什么@works正确而@fails1错误?
两者的匹配逻辑完全不同:
@works的逻辑是:匹配完全不包含任何禁用字符的字符串,也就是整个字符串里的所有字符都属于允许集合,完全符合你的需求。@fails1的逻辑是:匹配至少包含一个非禁用字符的字符串,只要字符串里有一个字符属于允许集合就会命中,哪怕剩下的全是禁用字符也会被保留,和你要的「所有字符都合规」的要求完全相悖。
这个问题和grep本身没有关系,只是正则匹配的适用场景不同:perlrecharclass里的示例是用于判断单个字符的归属,这种场景下/[^禁用集合]/和!/[禁用集合]/效果完全等价;但你现在要判断的是整个字符串的所有字符都符合要求,两种写法的逻辑就完全不一样了。
2. 为什么@fails2无法生效?
这和数组/列表上下文无关,是Perl数组在正则中插值的规则导致的:
数组直接插值到字符串/正则中时,默认会用特殊变量$"的值(默认是空格)拼接所有元素。你在正则中直接写[^@unwanted_letters],实际展开后是[^b e f g h j k l m p q r s u v w x y z],字符类里多了大量空格,完全不符合你预期的禁用字符集合。
之前筛选@unwanted_letters时能正常工作纯粹是歪打正着:当时你遍历的是单个小写字母(a-z),不可能匹配到字符类里的空格,所以空格的存在没有影响匹配结果,但用来匹配多字符单词时就会完全失效。
如果你要把数组元素拼接成字符类,正确写法是先手动拼接成无分隔符的字符串:
my $unwanted_str = join '', @unwanted_letters; my @result = grep(!/[$unwanted_str]/, @test_data);
3. 无需差集计算的纯正则方案
直接用锚定规则限定整个字符串的字符范围即可,不需要提前计算禁用字符集合:
my $wanted_str = join '', @wanted_letters; my @result = grep(/^[$wanted_str]+$/, @test_data);
这段正则的逻辑是:从字符串开头到结尾,所有字符都属于允许的字符集合,完全匹配你的需求,写法更简洁。
内容的提问来源于stack exchange,提问作者Hex
相关产品推荐
相关产品推荐

