2

我编写了一个 Perl 函数来替换 JCL 脚本中的作业名称。这里使用了零宽度匹配。

sub modify_jcl_jobname ()
{
    my ($jcl, $old, $new) = @_;

    $jcl =~ s/
         # The name must begin in column 3.
         ^(?<=\/\/)     

         # The first charater must be alphabetic or national.
        ($old)

         # The name must be followed by at leat on blank.
         # Append JCL keyword JOB 
        (?=\s+JOB)
       /$new/xmig; # Multi-lines, ignore case.

    return $jcl;
}

但是直到我做了一个简单的修改,删除了前导符号“^”,这个功能才起作用。

  #before  ^(?<=\/\/) 

  #after    (?<=\/\/) 

所以我想把问题的原因说清楚。任何答复将不胜感激。谢谢。

4

2 回答 2

8

问题在于

^(?<=\/\/)

^仅当匹配后的点前面有两个字符时,该模式才会匹配//。这永远不会发生,因为/^/m匹配字符串的开头和换行符之后。

但是您不想在行首开始匹配。您想开始匹配 2 个字符。您实际上想要的是:

(?<=^\/\/)

做了一些改进后,代码如下:

sub modify_jcl_jobname {
    my ($jcl, $old, $new) = @_;
    $jcl =~ s{
         (?<= ^// )
         \Q$old\E
         (?= \s+ JOB )
    }{$new}xmig;

    return $jcl;
}

改进:

  • 删除了不正确的原型 ( ())。它迫使调用者告诉 Perl 忽略原型(通过使用&)。
  • 添加了代码 ( \Q...\E) 以在使用它之前将其内容$old转换为正则表达式模式。
  • 删除了不必要的捕获 ( (...))。
  • 将替换的分隔符(从s///s{}{})切换为需要较少的转义。
  • 删除了高度冗余的评论。(好的评论解释了为什么正在做某事而不是正在做什么。)

优化器可能会更好地处理这个版本:

$jcl =~ s{
     ^// \K
     \Q$old\E
     (?= \s+ JOB )
}{$new}xmig;
于 2012-09-06T15:48:46.737 回答
3

^符号与行首相匹配。然后你想要一些前面有两个斜杠的东西 - 如果下一个字符是该行的第一个字符,这些斜杠应该放在哪里?

s{^//
  ($old)
  ...
 }{//$new}xmig

应该工作:你不需要回头看。

更新:感谢 ikegami,我现在明白你为什么使用它了。您希望将 保留//在字符串中:好吧,您可以在替换中重复它们,或者将^字符移动到后视中。

于 2012-09-06T15:35:39.440 回答