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

Raf*_*fal 5 php regex apache perl sed

基本问题

编码

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

脚本

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

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

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

示例文本文件以重新创建问题:

Lorem ipsum “dolor sit amet,” consectetur adipisicing elit. Numquam eos quos veniam iste.
Run Code Online (Sandbox Code Playgroud)

命令行和Web浏览器

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

1)我正在通过键入在Ubuntu 13.10上的命令行执行它 ./script.sh text-file

2)我通过使用以下代码处理Web表单并执行脚本,通过Web浏览器(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');
Run Code Online (Sandbox Code Playgroud)

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

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

Lorem ipsum “dolor sit amet,” consectetur adipisicing elit. Numquam eos quos veniam iste.
Run Code Online (Sandbox Code Playgroud)

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

Lorem ipsum“dolor sit amet,” consectetur adipisicing elit. Numquam eos quos veniam iste.
Run Code Online (Sandbox Code Playgroud)

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

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

我应该用:

#!/bin/bash
sed -r 's: ”:”:g' -i $1
Run Code Online (Sandbox Code Playgroud)

它从命令行和使用PHP都可以正常工作.

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

所以问题是 - 为什么PHP会修改我的脚本(sed)的工作方式?难道我做错了什么?看起来捕获组是问题的一部分,但我不明白为什么在脚本只是从命令行执行时不是这种情况.


发现

当我试图了解造成问题的原因时,我发现在sed和perl one-liners中有关捕获组的更多有趣和令人惊讶的事情.

下面的所有示例都在bash脚本中使用.

#!/bin/bash
example code
Run Code Online (Sandbox Code Playgroud)

起点是:

sed -r 's: ([”]):\1:g' -i $1
Run Code Online (Sandbox Code Playgroud)

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

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

perl -i -pe 's| ([”])|\1|smg' $1
Run Code Online (Sandbox Code Playgroud)

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

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

sed -r 's: [”]:”:g' -i $1
Run Code Online (Sandbox Code Playgroud)

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

perl -i -pe 's| [”]|”|smg' $1
Run Code Online (Sandbox Code Playgroud)

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

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

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

AKH*_*and 1

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

\n\n
s/ [\\xe2\\x80\\x9d]/\\xe2\\x80\\x9d/g\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

use utf8在 perl 中,可以通过在脚本顶部添加来解决此问题。对于 sed 示例,我预计LANGapache 和 shell 之间的环境变量是不同的,这会产生类似的效果。这可以通过设置来解决LANG明确设置该命令来修复:

\n\n
LANG="en_US.UTF-8" sed -r \'s: [\xe2\x80\x9d]:\\1:g\' -i $1\n
Run Code Online (Sandbox Code Playgroud)\n