2

我需要从 Bash 脚本对 PHP 文件(确切地说是 PHTML 文件,但它们仍然是有效的 PHP 文件)进行一些修改。我最初的想法是在正则表达式中使用 sed 或类似的实用程序,但是在这里阅读一些关于其他 HTML 解析问题的回复,似乎可能有更好的解决方案。

我在使用正则表达式时遇到的问题是缺乏对检测我想要匹配的字符串是否的支持:(src|href|action)=["']/是否在<?php ?>标签中,因此如果匹配在 PHP 标签中,我可以执行字符串连接,或者添加新的PHP标签不应该是。例如:

(1) <img id="icon-loader-small" src="/css/images/loader-small.gif" style="vertical-align:middle; display:none;"/>
(2) <li><span class="name"><?php echo $this->loggedInAs()?></span> | <a href="/Login/logout">Logout</a></li>
(3) <?php echo ($watched_dir->getExistsFlag())?"":"<span class='ui-icon-alert'><img src='/css/images/warning-icon.png'></span>"?><span><?php echo $watched_dir->getDirectory();?></span></span><span class="ui-icon ui-icon-close"></span>
(EDIT: 4) <form method="post" action="/Preference/stream-setting" enctype="application/x-www-form-urlencoded" onsubmit="return confirm('<?php echo $this->confirm_pypo_restart_text ?>');">

在 (1) 中有一个src="/css,因为它不在 PHP 标记中,所以我希望它变成src="<?php echo $baseUrl?>/css. 在(2)中,有一个 PHP 标签,但它不在 周围href="/Login,所以它也变成href="<?php echo $baseUrl?>/Login. 不幸的是,(3) 包含src='/cssPHP 标记内(它是一个回显字符串)。它也在PHP 代码中被引用,因此修改也需要注意这一点。最终结果将类似于:."src='".$baseUrl."/css

对我的 HTML 和 PHP 文件的所有其他修改都是使用正则表达式完成的(我知道,我知道......)。如果正则表达式可以支持匹配除特定模式之外的所有内容,[^(<\?php)(\?>)]*那么我会飞过这部分。不幸的是,这似乎是第 2 类语法领域。那么 - 我应该使用什么?理想情况下,它需要默认安​​装在 GNU 套件中,但其他工具(如 PHP 本身或其他解释器)也可以,只是不是首选。当然,如果有人可以构造一个适用于上述示例的正则表达式,那就太好了。

编辑:(4)是讨厌的匹配,大多数正则表达式都会失败。

4

1 回答 1

3

我解决这个问题的方法是将我的文件分成由 . 该脚本跟踪它当前所在的“上下文”——默认设置为 html,但在遇到这些标签时切换到 php。然后对该部分执行操作(不一定是正则表达式),然后将其附加到输出缓冲区。当文件被完全处理后,输出缓冲区被写回到文件中。

我试图用 sed 来做到这一点,但我遇到了无法控制在哪里打印换行符的问题。基于上下文的逻辑也是硬编码的,这意味着在新的上下文中添加会很乏味,例如 ASP.NET 支持。我目前的解决方案是用 Perl 编写的,可以缓解这两个问题,虽然我在让我的正则表达式实际做某事时遇到了一些麻烦,但这可能只是我错误地编码了我的正则表达式。

脚本如下:

#!/usr/bin/perl -w

use strict;

#Prototypes
sub readFile(;\$);
sub writeFile($);

#Constants
my $file;
my $outputBuffer;
my $holdBuffer;
# Regexes should have s and g modifiers
# Pattern is in $_
my %contexts = (
    html => {
        operation => ''
    },
    php => {
        openTag => '<\?php |<\? ', closeTag => '\?>', operation => ''
    },
    js => {
        openTag => '<script>', closeTag => '<\/script>', operation => ''
    }
);
my $currentContext = 'html';
my $combinedOpenTags;

#Initialisation
unshift(@ARGV, '-') unless @ARGV;
foreach my $key (keys %contexts) {
    if($contexts{$key}{openTag}) {
        if($combinedOpenTags) {
            $combinedOpenTags .= "|".$contexts{$key}{openTag};
        } else {
            $combinedOpenTags = $contexts{$key}{openTag};
        }
    }
}

#Main loop
while(readFile($holdBuffer)) {
    $outputBuffer = '';
    while($holdBuffer) {
        $currentContext = "html";
        foreach my $key (keys %contexts) {
            if(!$contexts{$key}{openTag}) {
                next;
            }
            if($holdBuffer =~ /\A($contexts{$key}{openTag})/) {
                $currentContext = $key;
                last;
            }
        }
        if($currentContext eq "html") {
            $holdBuffer =~ s/\A(.*?)($combinedOpenTags|\z)/$2/s;
            $_ = $1;
        } else {
            $holdBuffer =~ s/\A(.*?$contexts{$currentContext}{closeTag}|\z)//s;
            $_ = $1;
        }
        eval($contexts{$currentContext}{operation});
        $outputBuffer .= $_;
    }
    writeFile($outputBuffer);
}

# readFile: read file into $_
sub readFile(;\$) {
    my $argref = @_ ? shift() : \$_;
    return 0 unless @ARGV;
    $file = shift(@ARGV);
    open(WORKFILE, "<$file") || die("$0: can't open $file for reading ($!)\n");
    local $/;
    $$argref = <WORKFILE>;
    close(WORKFILE);
    return 1;
}

# writeFile: write $_[0] to file
sub writeFile($) {
    open(WORKFILE, ">$file") || die("$0: can't open $file for writing ($!)\n");
    print WORKFILE $_[0];
    close(WORKFILE);
}

我希望这可以被其他人使用和修改以满足他们的需要。

于 2012-11-02T18:06:21.347 回答