Sed正则表达式通过Web浏览器工作不同

时间:2014-04-07 14:55:15

标签: php regex apache perl sed

基本问题

编码

由于此问题看起来与编码有关,所有内容的编码 - 文本文件,bash脚本文件,终端,提供PHP脚本的网页,PHP脚本本身 - 都是UTF-8。

脚本

我确实有很长的bash脚本,它对文本文件执行一系列操作。出于此问题的目的,只有一个sed命令很重要:

#!/bin/bash   
sed -r 's: ([”]):\1:g' -i $1

它应该做的是在关闭智能报价之前删除空格。因为我使用更长的正则表达式和更多的字符并且希望捕获它以进行替换,因此存在括号和括号。

用于重新创建问题的示例文本文件:

Lorem ipsum “dolor sit amet,” consectetur adipisicing elit. Numquam eos quos veniam iste.

命令行和Web浏览器

我正在以两种方式使用这个bash脚本:

1)我通过输入./script.sh text-file

从Ubuntu 13.10的命令行执行它

2)我正在通过Web浏览器(Apache + PHP)执行它,使用以下代码来处理Web表单并执行脚本:

<?php

$file = "text-file";

move_uploaded_file($_FILES["file"]["tmp_name"], $file); 
shell_exec("./script.sh $file > /dev/null");
rename("$file", "output.html");
header('Content-Disposition: attachment; filename=output.html');
readfile('output.html');

问题是这样 - 当从命令行(1)执行时,脚本会给出另一个结果,而当通过Web浏览器(2 )执行时,脚本会产生其他结果。

从命令行(1)执行时,它什么都没有改变(因为在这种情况下没有任何改变),所以结果与输入相同(在这种情况下我希望实现输出):

Lorem ipsum “dolor sit amet,” consectetur adipisicing elit. Numquam eos quos veniam iste.

但是当它由PHP(2)执行时,它会在打开智能引号之前删除空格(根据使用的正则表达式,它不应该发生):

Lorem ipsum“dolor sit amet,” consectetur adipisicing elit. Numquam eos quos veniam iste.

经过多次测试,我发现不是使用:

#!/bin/bash   
sed -r 's: ([”]):\1:g' -i $1

我应该使用:

#!/bin/bash
sed -r 's: ”:”:g' -i $1

从命令行和使用PHP开始按预期工作。

然而,即使我解决了我的问题,现在它按照我想要的方式工作,我仍然不知道为什么PHP修改了我的脚本工作方式。

问题

所以问题是 - 为什么PHP会修改我的脚本(sed)的工作原理?我做错了什么?似乎捕获组是问题的一部分,但是我不明白为什么在脚本只是从命令行执行时不会出现这种情况。


发现

当我试图了解导致问题的原因时,我发现在sed和perl单行中有关捕获组的更多有趣和令人惊讶的事情。

以下所有示例均在bash脚本中使用。

#!/bin/bash
example code

起点是:

sed -r 's: ([”]):\1:g' -i $1

(如上所述)使用命令行(1)按预期工作,但在与PHP(2)一起使用时出现故障(删除空间)。

我使用perl one-liner进行相同的常规表达,看看问题是特定于sed还是更广泛(即与regexp或PHP相关的东西):

perl -i -pe 's| ([”])|\1|smg' $1

我发现它在命令行(1)和PHP(2)中都很糟糕(删除空间)。

之后,我尝试删除捕获组,并在sed表达式中只留下方括号:

sed -r 's: [”]:”:g' -i $1

从命令行(1)可以正常工作,但用PHP(2)在文本中创建了一些乱码。当使用perl测试相同的正则表达式时:

perl -i -pe 's| [”]|”|smg' $1

使用命令行(1)和PHP(2)导致输出乱码。

所以似乎一般问题(在打开智能引号之前删除空格)是由捕获组(括号)和方括号的组合引起的。 perl one-liner(来自命令行和PHP)和sed(仅使用PHP)都存在问题。

即使我知道如何摆脱这个问题(通过删除捕获括号和括号),我仍然很想知道为什么它以奇怪的方式工作以及实际导致问题的原因(PHP或Apache或组合) PHP / Apache和bash脚本)。

1 个答案:

答案 0 :(得分:1)

至少对于perl,如果脚本源中没有启用utf8,它会将看作几个单独的ASCII字符,最终将智能引用分成几部分。您使用的内容可以写成:

s/ [\xe2\x80\x9d]/\xe2\x80\x9d/g

这将匹配\xe2\x80\xe2)的某些部分,用结束引号替换它们,并留下一些不可打印的垃圾。

在perl中,这可以通过在脚本顶部添加use utf8来解决。使用sed示例,我希望apache和shell之间的LANG环境变量不同,这会产生类似的效果。这可以通过为该命令显式设置LANG来解决:

LANG="en_US.UTF-8" sed -r 's: [”]:\1:g' -i $1