Perl: глобальное замещение в строке с разделителями тегов - PullRequest
2 голосов
/ 01 августа 2010

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

<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 приводит к более чем одной замене на строку, но только для первого экземпляра на скобку тега (и только если обе круглые скобки содержат знак вопроса).

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

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

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

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

Это, конечно, также заменит скобки вне тегов.

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

Ответы [ 2 ]

1 голос
/ 01 августа 2010

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

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

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

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

my $n = 1;
$n = s/YOUR_REGEX/YOUR_REPLACE/g while $n;
0 голосов
/ 01 августа 2010

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

$_ = 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...