Почему $ 1 пусто в моей замене? - PullRequest
3 голосов
/ 05 декабря 2008

Я пытаюсь поместить содержимое в скобках в значение атрибута src в теге img:

while(<TOCFILE>)
{
    $toc_line = $_;
    $toc_line =~ s/<inlineFig.*?(\.\.\/pics\/ch09_inline99_*?\.jpg)*?<\/inlineFig>/<img src="${1}" alt="" \/\>/g;
    $new_toc_file .= $toc_line;
}

Итак, я ожидал увидеть такие теги в выводе:

<img src="../pics/ch09_inline99_00" alt="" />

Но вместо этого я получаю:

<img src="" alt="" />

Ответы [ 3 ]

12 голосов
/ 05 декабря 2008

В вашем регулярном выражении есть ошибка, так что фраза никогда не будет ничего соответствовать:

inline99_*?\.jpg
        ^^^ 

Я думаю, вы забыли \d перед звездой, судя по данным примера, который вы пытаетесь сопоставить.

Вы даже не просите, чтобы оно совпадало, поскольку вы ставите *? после захваченной группы. Так что это просто ничего не соответствует. Так вот, что вы получаете: ничего.

Кроме того:

($PATTERN)*?

будет захватывать только последнюю найденную вещь. Это, вероятно, не то, что вы хотите, либо. Например:

$_ = 'one two three';
s/(\w+\s*)*/$1/;
print;

печатает "три".

3 голосов
/ 05 декабря 2008

1) можно использовать некоторые примеры того, что вы анализируете.

2) если использовать «x» в конце выражения, вы можете поместить пробел и комментарии в регулярное выражение, чтобы сделать его более понятным

3) Кроме того, разбив его, вы заметите, что во второй части содержимого () отсутствует совпадение с числами ... вместо этого ищется 0 или более '_' и прерывается при увидел цифры, таким образом, не совпадают.

while(<TOCFILE>)
{
    $toc_line = $_;
    $toc_line =~ 
      s/                  # replace the follwoing     

         <inlineFig                     # match this text             
         .*?                            # then any characters until the next sequence matches
         (                              # throw the match into $1
            \.\.\/pics\/ch09_inline99_  # ..\pics\cho9_inline99_
            \d*?\.jpg                   # folowed by 0 or more numbers
         )*?                            # keeping doing that until the next sequence matches
         <\/inlineFig>                  # match this text

       /                  # with the follwoing


         <img src="${1}" alt="" \/\>    # some text and the result of $1 above.

       /xg;  # <- the x makes it ignore whitespace and #comments
    $new_toc_file .= $toc_line;
}

4) как уже упоминалось, () *? возвращает только последнее совпадение в $ 1, но это не должно быть проблемой, если ваш ввод будет только определенного формата.

1 голос
/ 05 декабря 2008

Исправьте ваш паттерн, как предложил Барт, и рассмотрите возможность использования переменной $ topic $ вместо явного присвоения данных, считанных из дескриптора файла, другой переменной.

#!/usr/bin/perl

use warnings;
use strict;

my $new_toc_file;

{
    # localizing $_ protects any existing value in the global $_
    # you should localize $_ even if you choose to assign it to a variable

    local $_;

    while(<DATA>) { 
        # in the absence of the bind operator =~, s/// operates against $_
        s!<inlineFig.*?(\.\./pics/ch09_inline99_.*?\.jpg)</inlineFig>!<img src="$1" alt="" />!g;
        $new_toc_file .= $_;
    }
}

print $new_toc_file, "\n";

__END__
<inlineFig>../pics/ch09_inline99_00.jpg</inlineFig>
...