代码之家  ›  专栏  ›  技术社区  ›  Andrew

为什么变量不能正确插入Perl替换模式?

  •  1
  • Andrew  · 技术社区  · 17 年前

    我正在编写一个复杂的脚本,它获取一个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:>

    下面是我的代码(在现实生活中)的工作摘录 $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 回复  |  直到 9 年前
        1
  •  11
  •   Chas. Owens    17 年前

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

    你做错的第二件事是说 {$IDsmall} 在正则表达式中。这意味着一个文字{变量的内容然后是文字}。由于文本版本中有文字大括号,我想您是想键入 ${IDsmall} 但是,这是不必要的,因为只有在您必须明确什么是变量以及什么是文本时才需要大括号 /${IDsmall}some other text/

    /\Q$IDsmall\E/ . 当然,如果您想让特殊字符影响匹配,那么就不应该使用普通字符串。您应该使用由 qr// 操作人员

    <[^~~](?:[^>'"]*|(['"]).*?\1)*> . /[^~~]/ /[^~]/ /[^~]{2}/ .

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

        2
  •  3
  •   kbosak    17 年前

    尝试将您的“$”放在“{”之外,如下所示:

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