Почему мои переменные не интерполируются правильно в мой шаблон подстановки Perl? - PullRequest
1 голос
/ 11 июня 2009

Я пишу сложный сценарий, который берет XML-резервную копию блога Blogger и преобразует его в текст с тегами InDesign для размещения в книге. Я использую целую кучу регулярных выражений, чтобы очистить теги HTML каждого сообщения в блоге и преобразовать их в теги InDesign. Например:

<p>A really long paragraph.</p> -> <ParaStyle:Main text>A really long paragraph.
<em>Whatever</em> -> <CharStyle:Italic>Whatever<CharStyle:>

По большей части скрипт работает отлично. Однако InDesign не может обрабатывать вложенные теги. <CharStyle:Small><CharStyle:Italic>This is small italic text<CharStyle:><CharStyle:> не будет работать и должен закончиться как <CharStyle:Small italic>This is small italic text<CharStyle:>

Я пытаюсь использовать переменные в шаблонах поиска регулярных выражений, чтобы найти где-нибудь, где теги стиля символа удваиваются, но когда я использую переменные, ничего не найдено. Однако, если я жестко закодирую теги InDesign в регулярное выражение, это работает. Что делает переменные неразборчивыми?

Вот рабочая выдержка из моего кода (в реальной жизни $input это не строковая переменная, а объект LibXML, который скрипт анализирует ... это только для иллюстрации)

#!/usr/bin/perl -w
use strict;

my $IDitalic = "<~~CharStyle:Italic>";
my $IDsmall = "<~~CharStyle:Small>";
my $IDsmallitalic = "<~~CharStyle:Small italic>";
my $IDcharend = "<~~CharStyle:>";

sub cleanText {
    my $text = $_[0];

    # Replace any span with a font size attribute with "small" character style
    $text =~ s/<span[^>]*?font-size[^>]*>(.*?)<\/span>/$IDsmall$1$IDcharend/gis;

    # Replace <em> tags with "italic" character style
    $text =~ s/<em>(.*?)<\/em>/$IDitalic$1$IDcharend/gis;

    #--------------------------------------------------------
    # Problem section
    #
    # The following works since everything is hard coded
    # $text =~ s/<~~CharStyle:Small><~~CharStyle:Italic>/$IDsmallitalic/gi;
    # $text =~ s/<~~CharStyle:><~~CharStyle:>/$IDcharend/gi;

    # When I use variables, though, it doesn't work...
    $text =~ s/{$IDsmall}{$IDitalic}/$IDsmallitalic/gi;
    $text =~ s/({$IDcharend})\1+/$1/gi;

    #--------------------------------------------------------


    # Clear out all tags that aren't the InDesign tags, take out the dummy ~~ and rebuild the actual tag
    $text =~ s/<[^~~](?:[^>'"]*|(['"]).*?\1)*>//gs;
    $text =~ s/<~~/</gs;

    return $text;
}

my $input = "<~~ParaStyle:Main text>In sodales malesuada nisi quis varius. Proin a ligula mauris. Proin ac justo est, vitae sollicitudin tortor. Proin auctor, <span style=\"font-size:78%\">augue eu</span> fringilla imperdiet, nisi sapien tempus libero, sed aliquet quam metus vel risus. Curabitur feugiat tristique porttitor. Integer malesuada volutpat accumsan. <span class=\"dummy\"In egestas</span> metus ut erat placerat tempus. <em>Nam vestibulum</em>, est quis scelerisque tincidunt, enim est lacinia ligula, vel accumsan ante nisl consectetur massa. Nullam velit nisi, viverra quis viverra ac, dictum ac enim. Sed nisl magna, fringilla at placerat quis, facilisis id nibh. Mauris eget sapien mauris, nec sollicitudin urna. Curabitur ac nunc a arcu vulputate tincidunt.\n<~~ParaStyle:Main text><span style=\"font-size:78%\"><em>**This is really small text</em></span>\n<ParaStyle:Comments\:Comment author>Andrew\n<~~ParaStyle:Comments\:Comment date>Friday, May 29, 2009— 8:15 PM";


print cleanText($input);

Итак, что же не так?

Кроме того, есть ли лучший способ сохранить теги InDesign без наличия фиктивных тильд в имени переменной?

Спасибо!

Автор, очевидно, решил разобрать HTML, для получения дополнительной информации перейдите к последующему разбору вопроса .

Ответы [ 2 ]

11 голосов
/ 11 июня 2009

Первое, что вы делаете неправильно, пытаетесь использовать регулярные выражения в XML, как вы заметили, это не работает. Это фундаментальное ограничение регулярных выражений. Вы должны использовать парсер вместо этого. Мне нравится XML::Twig.

Второе, что вы делаете неправильно, говорит {$IDsmall} в регулярном выражении. Это означает литерал {содержимое переменной, затем литерал}. Так как буквенные фигурные скобки есть в ваших текстовых версиях, я предполагаю, что вы хотели набрать ${IDsmall}, однако это не нужно, потому что фигурные скобки нужны только тогда, когда вы должны четко указать, что такое переменная и что такое текст /${IDsmall}some other text/. В этом случае без фигурных скобок Perl подумал бы, что вы имеете в виду переменную с именем $ IDsmallsome.

Третье, что вы делаете неправильно, - это не использование \ Q и \ E для предотвращения влияния специальных символов в ваших переменных на совпадение: /\Q$IDsmall\E/. Конечно, если вы хотите, чтобы специальные символы влияли на совпадение, вам не следует использовать обычную строку. Вы должны использовать регулярное выражение в кавычках, созданное оператором qr//.

Четвертая вещь, которую вы делаете неправильно, - это попытка использовать класс отрицанных символов для соответствия более чем одному символу: <[^~~](?:[^>'"]*|(['"]).*?\1)*>. /[^~~]/ означает то же самое, что и /[^~]/. Вы, вероятно, хотите /[^~]{2}/.

Могут быть и другие проблемы, это было то, что я видел на первый взгляд.

3 голосов
/ 11 июня 2009

Попробуйте поставить '$' за пределами '{' .. вот так:

$text =~ s/${IDsmall}${IDitalic}/$IDsmallitalic/gi;
$text =~ s/(${IDcharend})\1+/$1/gi;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...