我需要从bash脚本中对PHP文件进行一些修改(确切地说是PHTML文件,但它们仍然是有效的PHP文件)。我最初的想法是将SED或类似的实用程序与Regex一起使用,但是在这里阅读一些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='/css
,但是 php标签(这是一个回声的字符串)。"
在PHP代码中也引用了它,因此修改也需要对此进行拾取。最终结果看起来像:src='".$baseUrl."/css
。
对我的HTML和PHP文件进行的所有其他修改都是使用正则表达式完成的(我知道,我知道...)。如果Regexes可以支持匹配除特定模式(例如[^(<?php)(?>)]*
)以外的所有内容,那么我将在此部分中飞行。不幸的是,这似乎是2型语法领域。那么 - 我应该使用什么?理想情况下,默认情况下,它需要使用GNU套件安装,但是其他工具(例如PHP本身或其他口译器)也不错,只是不受欢迎。当然,如果某人可以构建将在上述示例上起作用的正则义务,那将是很棒的。
编辑:(4)是令人讨厌的匹配,大多数言论将失败。
我解决这个问题的方式是将文件分为封装的部分。该脚本跟踪当前所在的"上下文" - 默认设置为HTML,但在击中这些标签时切换到PHP。然后,操作(不一定是正则表达式)在该部分上执行,然后将其附加到输出缓冲区。完全处理文件后,输出缓冲区将写回文件中。
我试图使用SED进行此操作,但我面临无法控制新线的印刷位置的问题。基于上下文的逻辑也是硬编码的,这意味着在新的上下文中添加例如ASP.NET支持,这将是很乏味的。我目前的解决方案是用perl编写的,并减轻了这两个问题,尽管我遇到了一些麻烦,让我的正则要做一些事情,但这可能只是我错误地编码我的regex。
脚本如下:
#!/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);
}
我希望可以使用其他人来适应他们的需求。