为什么我的变量没有正确插入我的Perl替换模式?

时间:2009-06-11 13:17:57

标签: regex perl

我正在编写一个复杂的脚本,该脚本接受Blogger博客的XML备份,并将其转换为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,有关更多信息,请转到parsing follow-up question

2 个答案:

答案 0 :(得分:11)

你做错的第一件事是尝试在XML上使用正则表达式,正如你所注意到的那样,它不起作用。这是正则表达式的基本限制。您应该使用解析器。我喜欢XML::Twig

你做错的第二件事是在正则表达式中说{$IDsmall}。这意味着文字{变量的内容然后是文字}。由于文字花括号在您的文本版本中,我假设您打算键入${IDsmall},但是,这是不必要的,因为仅当您必须明确什么是变量以及什么是这样的文本时才需要花括号/${IDsmall}some other text/。在这种情况下,没有花括号Perl会认为你指的是一个名为$ IDsmallsome的变量。

你做错的第三件事是不使用\ Q和\ E来防止变量中的特殊字符影响匹配:/\Q$IDsmall\E/。当然,如果您想要使特殊字符影响匹配,那么您不应该使用普通字符串。您应该使用由qr//运算符生成的带引号的正则表达式。

你做错的第四件事是尝试使用否定的字符类来匹配多个字符:<[^~~](?:[^>'"]*|(['"]).*?\1)*>/[^~~]//[^~]/的含义相同。您可能需要/[^~]{2}/

可能还有其他问题,这些只是我第一眼看到的问题。

答案 1 :(得分:3)

尝试将'$'放在'{'......之外:

$text =~ s/${IDsmall}${IDitalic}/$IDsmallitalic/gi;
$text =~ s/(${IDcharend})\1+/$1/gi;