php - Sed 正则表达式通过 Web 浏览器的工作方式有所不同

原文 标签 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.

命令行和网络浏览器

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

1) 我在 Ubuntu 13.10 的命令行中输入 ./script.sh text-file 来执行它

2)我通过网络浏览器(Apache + PHP)执行它,使用以下代码处理网络表单并执行脚本:
<?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) 执行时,它会在打开 smart quote 之前删除空格(根据使用的正则表达式,这不应该发生):
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 one-liners 中的捕获组更有趣和令人惊讶的事情。

下面的所有示例都在 bash 脚本中使用。
#!/bin/bash
example code

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

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

我使用了与 perl one-liner 相同的正则表达式来查看问题是特定于 sed 还是更广泛(即 - 与正则表达式或 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 脚本)。

最佳答案

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

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

这将匹配一些 ( \xe2\x80\xe2 ),用结束语替换它们,并留下一些无法打印的垃圾。

在 perl 中,这是通过添加 use utf8 来解决的。在脚本的顶部。对于 sed 示例,我希望 LANG apache 和您的 shell 之间的环境变量不同,这会产生类似的效果。这可以通过设置 LANG 来解决明确用于该命令:
LANG="en_US.UTF-8" sed -r 's: [”]:\1:g' -i $1

关于php - Sed 正则表达式通过 Web 浏览器的工作方式有所不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22915972/

相关文章:

java - Android:将字符串读取为特定字符

java - 正则表达式在运算符之后拆分数学表达式并查找负数

apache - Webmin 登录不断循环到 session_login.cgi

apache - 在 tomcat7 中设置子域

php - 显示最后插入或最后更新的行

php - 从MySQL表中删除批量数据

php - 每天自动重置RESET值

php - 如何使用 PHP 向用户发送每日电子邮件通知?

python - 正则表达式匹配 key ,除了一个

linux - 指向Amazon Linux AMI测试页而非WP网站的AWS EC2实例