2

我想知道是否有一种优雅的方式可以将一个预编译的正则表达式与另一个匹配?我想不会,但还是决定问问。

说,我想在 Puppet 的 node.pp 中找到与特定模式相对应的所有节点。问题是,节点名称可以(并且通常是)定义为正则表达式本身。例如,可能需要查找“生产”环境中的所有节点,按照惯例,所有节点都以“p”开头,后跟 1 或 2 /^p[12].+$/。换句话说,

p(1|2)proxy-[1-4].domain.lan
p1smtp-[1-2].domain.lan
p[12]what-not-[1-8].domain.lan

应该匹配,而

q(1|2)proxy-[1-4].domain.lan
q(1|2)smtp-[1-2].domain.lan
q(1|2)what-not-[1-8].domain.lan

不应该。

目标字符串(如果编译为正则表达式)都是更通用表达式的子情况。所以我想知道,是否有任何捷径?

当然,可以将节点名称匹配为包括所有“正则表达式”变体在内的文字字符串——在这种特殊情况下应该不难。

4

1 回答 1

4

“如果你能想到的话,有一个 CPAN 模块可以做到这一点”。这就像 Perl 的第 34 条规则。

所以实际上存在Regexp::Compare,给定两个正则表达式字符串可以(有时)决定一个正则表达式是否匹配另一个正则表达式的真实子集。请注意,为了实现这一点,我在一开始就锚定了您的输入正则表达式。如果可以匹配所有匹配的字符串,则is_less_or_equal返回 true 。$metarx$rx

use strict; use warnings; use 5.010;
use Regexp::Compare qw(is_less_or_equal);

my @rx = (
  'p(1|2)proxy-[1-4].domain.lan',
  'p1smtp-[1-2].domain.lan',
  'p[12]what-not-[1-8].domain.lan',
  'q(1|2)proxy-[1-4].domain.lan',
  'q(1|2)smtp-[1-2].domain.lan',
  'q(1|2)what-not-[1-8].domain.lan',
);
my $metarx = '^p[12]';

for my $rx (@rx) {
  say "/$metarx/ ≥ /^$rx/ ?\t", is_less_or_equal("^$rx", $metarx) ? "yes" : "no";
}

输出:

/^p[12]/ ≥ /^p(1|2)proxy-[1-4].domain.lan/ ?    yes
/^p[12]/ ≥ /^p1smtp-[1-2].domain.lan/ ?         yes
/^p[12]/ ≥ /^p[12]what-not-[1-8].domain.lan/ ?  yes
/^p[12]/ ≥ /^q(1|2)proxy-[1-4].domain.lan/ ?    no
/^p[12]/ ≥ /^q(1|2)smtp-[1-2].domain.lan/ ?     no
/^p[12]/ ≥ /^q(1|2)what-not-[1-8].domain.lan/ ? no

我相信这符合您的想法。(注意:不要使用正则表达式对象,而只是使用普通字符串——这个模块可能在某些字符串化方面有困难)

于 2013-05-11T15:00:38.880 回答