我需要从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='/css
但里面 PHP标签(它是一个回显的字符串)。它在PHP代码中也由"
引用,因此修改也需要了解它。最终结果类似于:src='".$baseUrl."/css
。
我的HTML和PHP文件的所有其他修改都是使用正则表达式完成的(我知道,我知道......)。如果正则表达式可以支持匹配除某个模式之外的所有内容,例如[^(<\?php)(\?>)]*
,那么我将会飞过这一部分。不幸的是,这似乎是Type 2语法领域。所以 - 我该怎么用?
理想情况下,它需要默认安装GNU套件,但其他工具,如PHP本身或其他解释器也很好,只是不喜欢。当然,如果有人可以构建一个适用于上述示例的正则表达式,那么这将是非常好的。
编辑:(4)是令人讨厌的比赛,大多数正则表达式都会失败。
答案 0 :(得分: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);
}
我希望其他人可以使用和修改它以满足他们的需求。