有没有更好的方法来保存 Perl 中正则表达式的替换部分?
Is there better way to save the substitution part of regular expression in Perl?
$search_32bit = '(80 71 C3 (\S{8}) (77 55 66))';
$search_32bit =~ s/\s+//g;
$replace_32bit = 'A0 B0 C0 ';
$replace_32bit =~ s/\s+//g;
@repls_32 = (
[ $search_32bit, $replace_32bit],
);
$hex = "9090908071C312345678775566000000777777";
foreach my $r (@repls_32) {
$hex_tmp = $hex;
(my $s_sign, my $mat_pos) = eval "$hex =~ s/$r->[0]/$r->[1]/i;return ($1, $-[0])";
$len = length($s_sign);
$replaced_str = substr($hex, $mat_pos, $len);
print "matched_str: $s_sign\n";
print "mat_pos: $mat_pos\n";
print "length: $len\n";
print "replaced_str: $replaced_str\n";
}
输出如下:
matched_str: 8071C312345678775566
mat_pos: 6
length: 20
replaced_str: A0B0C012345678775566
我的问题:
是否有更好的方法来保存正则表达式的替换部分(即 $replaced_str: A0B0C012345678775566)?
一种获取替换字符串的方法,大概是作为正则表达式动态构建的 运行s
my $repl_str;
$str =~ s{$pattern}{ $repl_str = code-to-build-replacement }e;
具体示例:用句点填充捕获
my $str = 'funny';
my $repl_str;
$str =~ s{ (.{3}) }{ $repl_str = '.' . . '.' }ex;
say $repl_str; #--> .fun.
say $str; #--> .fun.ny
重点是替换部分里面的赋值表达式returns也是一样(赋值),所以替换字符串对regex还是可用的;这样做不会破坏事情。虽然现在有另一个变量浮动,但我认为没有用于替换字符串的内置正则表达式变量。
根据替换,仅通过添加该分配并不总是有效;回想一下 /e
的替代方是 code。因此,上面“正常”替换(没有 /e
)中的 ..
必须调整为有效代码,其中 '.'
字符串连接到 [=23= 的捕获] 运算符,然后我们可以添加赋值和 运行 that.
我希望你能将它改编成那个 eval
,为此我不知道你为什么需要它——除了也许 运行 从外部提供的代码,作为细绳?即便如此,我希望只提供部分正则表达式,您仍然可以编写正则表达式并可以执行上述操作。
澄清问题中的一些要点会有所帮助,但希望这对目前的情况有用。 (如果可能,将来考虑为您的需要构建一个简单明了的示例。)
在这种特定情况下,那些 </code>(等)似乎是捕获组,这是一个复杂的问题。然后他们需要 <code>
(等),并且需要更多的工作来使用变量
一种方法是根据给定的 $replace
字符串构建实际的替换字符串
use warnings;
use strict;
use feature 'say';
my $str = shift // '9090908071C312345678558765432166aaaabbbb7700abc' ;
say $str;
my $search = qr/8071C3(\S{8})55(\S{8})66(\S{8})77/;
my $replace = q(A0B0C0567);
my $repl_str;
$str =~ s/$search/$repl_str = build_repl($replace, , , )/e;
# or use @{^CAPTURE} instead of ,, with perl-5.27.2 or newer
say $str;
say $repl_str;
sub build_repl {
my ($r, @captures) = @_;
my @terms = grep { $_ } split /($\d)/, $r;
# Terms that start with $ are $N's and are picked from input
my $str = join '', map { /^$/ ? shift(@captures) : $_ } @terms;
return $str;
}
请参阅下面的讨论。† 这会打印出
9090908071C312345678558765432166aaaabbbb7700abc
909090A0B0C012345678558765432166aaaabbbb7700abc
A0B0C012345678558765432166aaaabbbb77
(这是正确的,虽然很难看清。为什么一个问题中的示例这么长且难以阅读?)
我使用 qr to build a regex pattern, but ''
(or q()
) works here as well. Since 5.27.2 there is a builtin @{^CAPTURE} variable 所以也许可以使用它来代替显式的 ,,...
列表。
一个类似的例子有更多的解释可以在
。当然,还有其他方法可以组织代码来构建替换字符串,并且还有一些有用的库。
上面的 sub 进行了捕获,因此手头有它们,可以编写替换字符串。 /e
是必需的,以便 运行 正则表达式中的子,一旦捕获可用。
链接的答案构建 code 并使用 /ee
。请仔细阅读相关警告并点击链接。我看不出这里需要那个。
†这是评论中对上面是否可以简化的讨论
替换端的任何变量,包括 $N
,都将被评估并与任何文字字符串连接成替换字符串。
my $str = 'bc';
$str =~ s/(.)/a/; #--> abc
但是当替换对象在变量中时,就不一样了。有
$r = "a"; # Interpreter doesn't know what "" is
$str =~ s/(.)/a/; #--> Use of uninitialized value ...
如果我们尝试使用单引号,那么这就是我们得到的,仅仅是文字字符 a
和 $
和 1
$r = 'a'; # now it won't try to evaluate ...
$str =~ s/(.)/a/; #--> ac (but it doesn't do it here either)
那么我们如何让它把</code>放在替换端<em>并且</em>把它当作一个变量来评估呢?</p>
<p>这就是 <code>/e
修饰符的用途,我们变量中的字符串现在必须具有有效代码的语法。然而,这仍然不足以获得 </code> 评估;整个工作需要 <code>/ee
$r = q('a'.);
$str =~ s/(.)/a/ee; #--> abc (that /ee is very unsafe)
但这有点复杂,给定的$r
(问题中的$replace
)必须处理成有效的代码语法,我们正在打开一个巨大的安全漏洞,因为/ee
将任何字符串评估为代码,然后在该字符串中评估代码。 (点击文本中链接的 post 中的链接。)
那么为什么不直接使用我们传递给 $N
s 的函数,它经过很好的评估,因此该函数可以获得实际捕获的字符串。然后在函数中我们可以解析 $r
并构建我们的替换字符串。
那么 build_repl
对 的作用是 所需要的。 (这就是为什么有它的库。)
尝试这些事情的一种方法是使用像
这样的“单行”
perl -wE'$_ = q(bc); $r = q(a); s/(.)/$r/; say'
和
perl -wE'$_ = q(bc); $r = q("a".); s/(.)/$r/ee; say'
q(...)
与单引号相同,而 qq(...)
与双引号相同。
首先,让我们修复您的错误。
use String::Substitution qw( sub_modify );
my $search = qr/(80 71 C3 (\S{8}) (77 55 66))/xi;
my $replace = 'A0 B0 C0 ' =~ s/\s+//gr; # should be in replacement.
sub_modify($hex, $search, $replace); # Fix code injection bugs
这相当于
use String::Substitution qw( sub_modify interpolate_match_vars );
my $search = qr/(80 71 C3 (\S{8}) (77 55 66))/xi;
my $replace = 'A0 B0 C0 ' =~ s/\s+//gr;
sub_modify($hex, $search, sub { interpolate_match_vars($replace, @_) });
现在,只是保存字符串的问题了。
use String::Substitution qw( sub_modify interpolate_match_vars );
my $search = qr/(80 71 C3 (\S{8}) (77 55 66))/xi;
my $replace = 'A0 B0 C0 ' =~ s/\s+//gr;
my $replacement_str;
sub_modify($hex, $search, sub { $replacement_str = interpolate_match_vars($replace, @_) });
不过,以上内容给人一种由内而外的感觉。可以如下翻转:
use String::Substitution qw( interpolate_match_vars last_match_vars );
my $search = qr/(80 71 C3 (\S{8}) (77 55 66))/xi;
my $replace = 'A0 B0 C0 ' =~ s/\s+//gr;
my $replacement_str;
if ($hex =~ $search) {
$replacement_str =
substr($hex, $-[0], $+[0] - $-[0]) =
interpolate_match_vars($replace, last_match_vars());
}
这也使得保存原始匹配变得容易。
use String::Substitution qw( interpolate_match_vars last_match_vars );
my $search = qr/(80 71 C3 (\S{8}) (77 55 66))/xi;
my $replace = 'A0 B0 C0 ' =~ s/\s+//gr;
my $match_str;
my $replacement_str;
if ($hex =~ $search) {
my $match_ref = \substr($hex, $-[0], $+[0] - $-[0]);
$match_str = $$match_ref;
$replacement_str = interpolate_match_vars($replace, last_match_vars());
$$match_ref = $replacement_str;
}
$search_32bit = '(80 71 C3 (\S{8}) (77 55 66))';
$search_32bit =~ s/\s+//g;
$replace_32bit = 'A0 B0 C0 ';
$replace_32bit =~ s/\s+//g;
@repls_32 = (
[ $search_32bit, $replace_32bit],
);
$hex = "9090908071C312345678775566000000777777";
foreach my $r (@repls_32) {
$hex_tmp = $hex;
(my $s_sign, my $mat_pos) = eval "$hex =~ s/$r->[0]/$r->[1]/i;return ($1, $-[0])";
$len = length($s_sign);
$replaced_str = substr($hex, $mat_pos, $len);
print "matched_str: $s_sign\n";
print "mat_pos: $mat_pos\n";
print "length: $len\n";
print "replaced_str: $replaced_str\n";
}
输出如下:
matched_str: 8071C312345678775566
mat_pos: 6
length: 20
replaced_str: A0B0C012345678775566
我的问题:
是否有更好的方法来保存正则表达式的替换部分(即 $replaced_str: A0B0C012345678775566)?
一种获取替换字符串的方法,大概是作为正则表达式动态构建的 运行s
my $repl_str;
$str =~ s{$pattern}{ $repl_str = code-to-build-replacement }e;
具体示例:用句点填充捕获
my $str = 'funny';
my $repl_str;
$str =~ s{ (.{3}) }{ $repl_str = '.' . . '.' }ex;
say $repl_str; #--> .fun.
say $str; #--> .fun.ny
重点是替换部分里面的赋值表达式returns也是一样(赋值),所以替换字符串对regex还是可用的;这样做不会破坏事情。虽然现在有另一个变量浮动,但我认为没有用于替换字符串的内置正则表达式变量。
根据替换,仅通过添加该分配并不总是有效;回想一下 /e
的替代方是 code。因此,上面“正常”替换(没有 /e
)中的 ..
必须调整为有效代码,其中 '.'
字符串连接到 [=23= 的捕获] 运算符,然后我们可以添加赋值和 运行 that.
我希望你能将它改编成那个 eval
,为此我不知道你为什么需要它——除了也许 运行 从外部提供的代码,作为细绳?即便如此,我希望只提供部分正则表达式,您仍然可以编写正则表达式并可以执行上述操作。
澄清问题中的一些要点会有所帮助,但希望这对目前的情况有用。 (如果可能,将来考虑为您的需要构建一个简单明了的示例。)
在这种特定情况下,那些 </code>(等)似乎是捕获组,这是一个复杂的问题。然后他们需要 <code>
(等),并且需要更多的工作来使用变量
一种方法是根据给定的 $replace
字符串构建实际的替换字符串
use warnings;
use strict;
use feature 'say';
my $str = shift // '9090908071C312345678558765432166aaaabbbb7700abc' ;
say $str;
my $search = qr/8071C3(\S{8})55(\S{8})66(\S{8})77/;
my $replace = q(A0B0C0567);
my $repl_str;
$str =~ s/$search/$repl_str = build_repl($replace, , , )/e;
# or use @{^CAPTURE} instead of ,, with perl-5.27.2 or newer
say $str;
say $repl_str;
sub build_repl {
my ($r, @captures) = @_;
my @terms = grep { $_ } split /($\d)/, $r;
# Terms that start with $ are $N's and are picked from input
my $str = join '', map { /^$/ ? shift(@captures) : $_ } @terms;
return $str;
}
请参阅下面的讨论。† 这会打印出
9090908071C312345678558765432166aaaabbbb7700abc 909090A0B0C012345678558765432166aaaabbbb7700abc A0B0C012345678558765432166aaaabbbb77
(这是正确的,虽然很难看清。为什么一个问题中的示例这么长且难以阅读?)
我使用 qr to build a regex pattern, but ''
(or q()
) works here as well. Since 5.27.2 there is a builtin @{^CAPTURE} variable 所以也许可以使用它来代替显式的 ,,...
列表。
一个类似的例子有更多的解释可以在
上面的 sub 进行了捕获,因此手头有它们,可以编写替换字符串。 /e
是必需的,以便 运行 正则表达式中的子,一旦捕获可用。
链接的答案构建 code 并使用 /ee
。请仔细阅读相关警告并点击链接。我看不出这里需要那个。
†这是评论中对上面是否可以简化的讨论
替换端的任何变量,包括 $N
,都将被评估并与任何文字字符串连接成替换字符串。
my $str = 'bc';
$str =~ s/(.)/a/; #--> abc
但是当替换对象在变量中时,就不一样了。有
$r = "a"; # Interpreter doesn't know what "" is
$str =~ s/(.)/a/; #--> Use of uninitialized value ...
如果我们尝试使用单引号,那么这就是我们得到的,仅仅是文字字符 a
和 $
和 1
$r = 'a'; # now it won't try to evaluate ...
$str =~ s/(.)/a/; #--> ac (but it doesn't do it here either)
那么我们如何让它把</code>放在替换端<em>并且</em>把它当作一个变量来评估呢?</p>
<p>这就是 <code>/e
修饰符的用途,我们变量中的字符串现在必须具有有效代码的语法。然而,这仍然不足以获得 </code> 评估;整个工作需要 <code>/ee
$r = q('a'.);
$str =~ s/(.)/a/ee; #--> abc (that /ee is very unsafe)
但这有点复杂,给定的$r
(问题中的$replace
)必须处理成有效的代码语法,我们正在打开一个巨大的安全漏洞,因为/ee
将任何字符串评估为代码,然后在该字符串中评估代码。 (点击文本中链接的 post 中的链接。)
那么为什么不直接使用我们传递给 $N
s 的函数,它经过很好的评估,因此该函数可以获得实际捕获的字符串。然后在函数中我们可以解析 $r
并构建我们的替换字符串。
那么 build_repl
对 的作用是 所需要的。 (这就是为什么有它的库。)
尝试这些事情的一种方法是使用像
这样的“单行”perl -wE'$_ = q(bc); $r = q(a); s/(.)/$r/; say'
和
perl -wE'$_ = q(bc); $r = q("a".); s/(.)/$r/ee; say'
q(...)
与单引号相同,而 qq(...)
与双引号相同。
首先,让我们修复您的错误。
use String::Substitution qw( sub_modify );
my $search = qr/(80 71 C3 (\S{8}) (77 55 66))/xi;
my $replace = 'A0 B0 C0 ' =~ s/\s+//gr; # should be in replacement.
sub_modify($hex, $search, $replace); # Fix code injection bugs
这相当于
use String::Substitution qw( sub_modify interpolate_match_vars );
my $search = qr/(80 71 C3 (\S{8}) (77 55 66))/xi;
my $replace = 'A0 B0 C0 ' =~ s/\s+//gr;
sub_modify($hex, $search, sub { interpolate_match_vars($replace, @_) });
现在,只是保存字符串的问题了。
use String::Substitution qw( sub_modify interpolate_match_vars );
my $search = qr/(80 71 C3 (\S{8}) (77 55 66))/xi;
my $replace = 'A0 B0 C0 ' =~ s/\s+//gr;
my $replacement_str;
sub_modify($hex, $search, sub { $replacement_str = interpolate_match_vars($replace, @_) });
不过,以上内容给人一种由内而外的感觉。可以如下翻转:
use String::Substitution qw( interpolate_match_vars last_match_vars );
my $search = qr/(80 71 C3 (\S{8}) (77 55 66))/xi;
my $replace = 'A0 B0 C0 ' =~ s/\s+//gr;
my $replacement_str;
if ($hex =~ $search) {
$replacement_str =
substr($hex, $-[0], $+[0] - $-[0]) =
interpolate_match_vars($replace, last_match_vars());
}
这也使得保存原始匹配变得容易。
use String::Substitution qw( interpolate_match_vars last_match_vars );
my $search = qr/(80 71 C3 (\S{8}) (77 55 66))/xi;
my $replace = 'A0 B0 C0 ' =~ s/\s+//gr;
my $match_str;
my $replacement_str;
if ($hex =~ $search) {
my $match_ref = \substr($hex, $-[0], $+[0] - $-[0]);
$match_str = $$match_ref;
$replacement_str = interpolate_match_vars($replace, last_match_vars());
$$match_ref = $replacement_str;
}