Perl 单元 2 正则表达式为 1

Perl unite 2 regexps into 1

有效的字符串应由西里尔字符或仅由拉丁字符组成。

我用 2 个正则表达式创建了一个有效的解决方案。但是当我试图将它们合并为 1 时,它失败了:

#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use v5.14;
use open ':std', ':encoding(UTF-8)';

my @data = (
    # rus - ok
    "абвгдеёжзийклмнопрстуфхцчшщьыъэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ",
    # space
    "а бвгдеёжзийклмнопрстуфхцчшщьыъэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ",
    # rus - latin
    "аtбвгдеёжзийклмнопрстуфхцчшщьыъэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ",
    # digit
    "аб2вгдеёжзийклмнопрстуфхцчшщьыъэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ",
    # latin - ok
    "abcdefghejklmnopqrstuvwxyzABCDEFGHEJKLMNOPQRSTUVWXYZ",
    # space
    "a bcdefghejklmnopqrstuvwxyzABCDEFGHEJKLMNOPQRSTUVWXYZ",
    # underscore
    "a_bcdefghejklmnopqrstuvwxyzABCDEFGHEJKLMNOPQRSTUVWXYZ",
    # digit
    "a2bcdefghejklmnopqrstuvwxyzABCDEFGHEJKLMNOPQRSTUVWXYZ"
);

foreach(@data) {
    if ($_ =~ /^[а-яё]+$/i or $_ =~ /^[a-z]+$/i) {
        print "ok\n";
    }
    else {
        print "bad\n";
    }
}

print "-------\n";
foreach(@data) {
    if ($_ =~ /^(:?[а-яё]+)|(:?[a-z]+)$/i) {
        print "ok\n";
    }
    else {
        print "bad\n";
    }
}

输出:

ok
bad
bad
bad
ok
bad
bad
bad
-------
ok
ok
ok
ok
ok
ok
ok
ok

出于某种原因,第二个正则表达式总是成功。

在你的正则表达式中,

  • :? - 当您想定义 non-capturing group(?:...)
  • 时匹配可选的 :
  • ^(?:a+)|(?:b+)$ - 匹配字符串开头的 a 或字符串结尾的 b

你应该使用

/^(?:[а-яё]+|[a-z]+)$/i

参见regex demo详情:

  • ^ - 字符串的开头
  • (?: - 非捕获组的开始
    • [а-яё]+ - 一个或多个俄语字母
    • | - 或
    • [a-z]+ - 一个或多个 ASCII 字母
  • ) - 非捕获组结束
  • $ - 字符串结尾。

注意:从 Perl 5.22 开始,您可以使用 n modifier 使捕获组表现为非捕获,/^([а-яё]+|[a-z]+)$/ni。因此,不存在混合 ?::?.

的风险

在这种情况下使用 use v5.22.0; 检查核心版本。