使用解析器标记删除PHP中允许的空白
我试图制作一个简单的脚本,从PHP文件/字符串中删除所有不必要的空白 我已经成功地使用标记解析了字符串,但是没有找到一个删除“额外”空白的好方法 比如说,使用解析器标记删除PHP中允许的空白,php,whitespace,minify,token,Php,Whitespace,Minify,Token,我试图制作一个简单的脚本,从PHP文件/字符串中删除所有不必要的空白 我已经成功地使用标记解析了字符串,但是没有找到一个删除“额外”空白的好方法 比如说, function test() { return TRUE; } 应该是 function test(){return TRUE;} 而不是 functiontest(){returnTRUE;} 如果只删除T_空白标记,则最终会得到最后一个版本 我是否缺少删除空格,但在“function”和“return”之后保留空格的功能。谢谢大家
function test() { return TRUE; }
应该是
function test(){return TRUE;}
而不是
functiontest(){returnTRUE;}
如果只删除T_空白标记,则最终会得到最后一个版本
我是否缺少删除空格,但在“function”和“return”之后保留空格的功能。谢谢大家! 嗯,
T_空格
可以是空格或换行符等。因此,一个简单的方法是自动将所有T_空格
实例替换为一个新实例,该实例正好由一个空格组成
但是对于一个更智能的方法,只需遍历,并找出哪些应该在后面有空格,哪些不应该(类似于下面的内容):
还有一点要注意,不要为了表现而这样做。如果您使用的是操作码缓存(如APC),那么大量工作将不会带来任何好处。如果你不使用,为什么不使用
$newSource = '';
foreach (token_get_all($source) as $i => $token) {
if (!is_array($token)) {
$newSource .= $token;
}
if ($token[0] == T_WHITESPACE) {
if ( isset($tokens[$i - 1]) && isset($tokens[$i + 1])
&& is_array($tokens[$i - 1]) && is_array($tokens[$i + 1])
&& isLabel($tokens[$i - 1][1]) && isLabel($tokens[$i + 1][1])
) {
$newSource .= ' ';
}
} else {
$newSource .= $token[1];
}
}
function isLabel($str) {
return preg_match('~^[a-zA-Z0-9_\x7f-\xff]+$~', $str);
}
除了两边都有标签的情况外,始终允许删除空白。我检查它,要么不添加任何内容,要么添加一个空格字符
我知道还有一个特例,空白很重要:T_END_herdoc
后面必须跟代码>或\n
。不允许压缩或剥离此处的空间。因此,如果这对您很重要,您可以简单地添加它;) 你的努力是徒劳的
php -w
允许已删除脚本中的空白。它使用更复杂的逻辑从令牌流中删除空白。
下面是zend_highlight.c
中的zend_strip()
函数:
while ((token_type=lex_scan(&token TSRMLS_CC))) {
switch (token_type) {
case T_WHITESPACE:
if (!prev_space) {
zend_write(" ", sizeof(" ") - 1);
prev_space = 1;
}
/* lack of break; is intentional */
case T_COMMENT:
case T_DOC_COMMENT:
token.type = 0;
continue;
case T_END_HEREDOC:
zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
efree(token.value.str.val);
/* read the following character, either newline or ; */
if (lex_scan(&token TSRMLS_CC) != T_WHITESPACE) {
zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
}
zend_write("\n", sizeof("\n") - 1);
prev_space = 1;
token.type = 0;
continue;
default:
zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
break;
}
if (token.type == IS_STRING) {
switch (token_type) {
case T_OPEN_TAG:
case T_OPEN_TAG_WITH_ECHO:
case T_CLOSE_TAG:
case T_WHITESPACE:
case T_COMMENT:
case T_DOC_COMMENT:
break;
default:
efree(token.value.str.val);
break;
}
}
prev_space = token.type = 0;
}
谢谢你。这是我想我可能不得不做的方法,有点痛苦!我已经有了单空格选项,但它有点像半个空格。@Matt:我真的不得不问,你为什么要这样做?目标是什么?目标的理由是什么?基本上是一个学术练习。我经常在随机的地方重复使用我的方法,有时候如果它们只占用一行就好了。我意识到这对速度/执行没有真正的影响。@Matt:好吧,很公平。仍然不是一个好主意(复制粘贴等)。最好使用库并包含功能,而不是复制它。但作为一项学术活动,我想一切都会发生…@nikic:这实际上是误导。-w
选项应该输出带有精简注释和空白的源代码。
-但它主要只是压缩它们。作为一个例子,这很有趣。是的,我知道php-w命令。徒劳可能有点过于戏剧化,我只想要一个一键函数,去掉我不需要的东西,并替换变量。谢谢你的推荐,很有趣。剧本很好,谢谢。它还与一个变量替换器一起工作。我在令牌上运行两个循环,首先捕获变量,然后在第二个循环中删除空白,然后替换变量。我还删除了注释,发现如果我尝试在一个循环中删除注释,那么注释原来所在的位置会有一个空间。在我的例子中,我将它移动到第一个循环,所有问题都解决了。*我发现除了“case”语句之外,这对我的许多文件都有效。例如,我的一个语句是检查http状态,而“case404:”变成了“case404:”,这显然是一个错误。我只是将那个else设置为elseif($token[0]==T_CASE){$new_source.=$token[1].';}(在标记后添加一个空格),然后继续执行当前的else语句。@Matt Gaidica:是的,我的错。我检查了PHP lexer定义为{LABEL}
的内容,但我也应该查找数字,因为它们也可以出现在标签中(除了第一个字符)。我调整了正则表达式。
while ((token_type=lex_scan(&token TSRMLS_CC))) {
switch (token_type) {
case T_WHITESPACE:
if (!prev_space) {
zend_write(" ", sizeof(" ") - 1);
prev_space = 1;
}
/* lack of break; is intentional */
case T_COMMENT:
case T_DOC_COMMENT:
token.type = 0;
continue;
case T_END_HEREDOC:
zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
efree(token.value.str.val);
/* read the following character, either newline or ; */
if (lex_scan(&token TSRMLS_CC) != T_WHITESPACE) {
zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
}
zend_write("\n", sizeof("\n") - 1);
prev_space = 1;
token.type = 0;
continue;
default:
zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
break;
}
if (token.type == IS_STRING) {
switch (token_type) {
case T_OPEN_TAG:
case T_OPEN_TAG_WITH_ECHO:
case T_CLOSE_TAG:
case T_WHITESPACE:
case T_COMMENT:
case T_DOC_COMMENT:
break;
default:
efree(token.value.str.val);
break;
}
}
prev_space = token.type = 0;
}