2010-08-01 1 views
2

Моя цель состоит в том, чтобы заменить все экземпляры привязанных к конечным + в тегах скобок. Давайте предположим, линию, которая будет заменена выглядит следующим образом:Perl: глобальная подстановка в строке с разделителями тегов

<h> aa- aa- </h> <h> ba- ba- </h> 

и должны впоследствии выглядеть

<h> aa+ aa+ </h> <h> ba+ ba+ </h> 

Сначала я попробовал это выражение:

s/<h>(.*?)-(.*?)<\/h>/<h>$1+$2<\/h>/g; 

, которые дали этот вывод:

<h> aa+ aa- </h> <h> ba+ ba- </h> 

g op что приводит к более чем одной подстановке на строку, но только для первого экземпляра для каждой привязки тега (и только если оба круглых скобки содержат знак вопроса).

Чтобы сузить проблему, я попытался добиться замещения без учета тегов. Выражение

s/(.*?)-(.*?)/$1+$2/g; 

действительно приводит к желаемому результату

<h> aa+ aa+ </h> <h> ba+ ba+ </h> 

Это будет заменить за пределами тега скобки, а также, конечно.

В чем проблема с моим первым выражением и как я могу достичь своей цели полной замены в скобках тегов?

+0

Если есть какие-либо ограничения на набор символов, который доходит до '-' вы можете использовать это. – adamse

+1

Вы должны использовать полноценный синтаксический анализатор, которые не являются регулярными выражениями. – Ether

ответ

0

Вот один из способов сделать это: разделите строку на тегированные биты и не отмеченные биты и выполните замену только на отмеченные биты.

$_ = join("", map { if(/^<h>/) { # if it's a tagged bit... 
         s/-($|\s|<)/+$1/g; # replace all trailing '-'s 
        } 
        $_} 
        split m!(<h>.*?</h>)!) # split into tagged and non-tagged bits 
1

Поскольку вы разбираете XML с регулярными выражениями (не очень хорошая идея в общем случае), я предполагаю, что вы готовы сделать несколько предположений о вашем входе. Если это так, следующая замена может быть достаточно хорошей.

Он заменяет знаки минуса знаками плюс, при условии, что знак минуса: (a) на границе слова и (b), за которым следует некоторый необязательный текст без левого угла, а затем тег закрытия. Не нужно беспокоиться о стартовом теге, если мы можем принять действительный документ. Второе условие принудительно выполняется с помощью прогнозного утверждения, так что регулярное выражение не будет потреблять строку, позволяя вам заменить все такие знаки минус.

s/ \b- (?= [^<]* <\/h>) /+/xg; 

Другой вариант - запустить регулярное выражение, пока оно не заменит что-либо. В скалярном контексте глобальная подстановка возвращает количество произведенных замен, которое может служить вашим тестом на то, когда прекратить обработку строки:

my $n = 1; 
$n = s/YOUR_REGEX/YOUR_REPLACE/g while $n; 
Смежные вопросы