Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't zero-width match regex work?

I wrote a Perl function to replace job name in JCL script. Zero-width match was used here.

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;
}

But this function didn't work until I did a simple modification that just deleted the leading sign "^".

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

  #after    (?<=\/\/) 

So I'd like to make it clear that the cause of problem. Any reply would be appreciated. Thanks.

like image 649
thinkhy Avatar asked Mar 02 '26 13:03

thinkhy


1 Answers

The problem lies with

^(?<=\/\/)

That pattern will only match if the spot after which ^ matched is preceded by the two characters //. That's never going to happen since /^/m matches the start of the string and after a newline.

But you don't want to start matching at the start of the line. You want to start matching 2 characters in. What you want is actually:

(?<=^\/\/)

After doing some improvements, the code looks like:

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

    return $jcl;
}

Improvements:

  • Removed the incorrect prototype (()). It forced the caller to tell Perl to ignore the prototype (by using &).
  • Added code (\Q...\E) to convert the contents of $old into a regex pattern before using it as such.
  • Removed the needless capture ((...)).
  • Switched the delimiters of the substitution (from s/// to s{}{}) to require less escaping.
  • Removed highly redundant comments. (Good comments explain why something is being done rather than what is being done.)

The optimiser might handle this version better:

$jcl =~ s{
     ^// \K
     \Q$old\E
     (?= \s+ JOB )
}{$new}xmig;
like image 69
ikegami Avatar answered Mar 04 '26 08:03

ikegami