php - 管道输入到 perl 进程自动解码 url 编码的字符串
php - Piping input to perl process automatically decodes url-encoded string
我正在使用 proc_open
将一些文本通过管道传输到 perl 脚本以加快处理速度。文本包括 url 编码的字符串以及文字 space。当 url 编码的 space 出现在原始文本中时,它似乎在到达 perl 脚本时被解码为文字 space。在 perl 脚本中,我依赖文字 spaces 的定位,所以这些不需要的 spaces 弄乱了我的输出。
为什么会发生这种情况,是否有办法防止这种情况发生?
相关代码片段:
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
);
$cmd = "perl script.pl";
$process = proc_open($cmd, $descriptorspec, $pipes);
$output = "";
if (is_resource($process)) {
fwrite($pipes[0], $raw_string);
fclose($pipes[0]);
while (!feof($pipes[1])) {
$output .= fgets($pipes[1]);
}
fclose($pipes[1]);
proc_close($process);
}
一行原始文本输入看起来像这样:
key url\tvalue1\tvalue2\tvalue3
我或许可以通过转换输入的格式来避免这个问题,但出于各种不希望的原因,并且绕过了而不是解决了关键问题。
此外,我知道问题发生在 php 脚本和 perl 脚本之间的某处,因为我在将其写入 perl 之前立即检查了原始文本(带有 echo
)脚本 STDIN 管道,我直接在 url 编码的原始字符串上测试了我的 perl 脚本。
我现在在下面添加了 perl 脚本。它基本上可以归结为一个小型 map-reduce 作业。
use strict;
my %rows;
while(<STDIN>) {
chomp;
my @line = split(/\t/);
my $key = $line[0];
if (defined @rows{$key}) {
for my $i (1..$#line) {
$rows{$key}->[$i-1] += $line[$i];
}
} else {
my @new_row;
for my $i (1..$#line) {
push(@new_row, $line[$i]);
}
$rows{$key} = [ @new_row ];
}
}
my %newrows;
for my $key (keys %rows) {
my @temparray = split(/ /, $key);
pop(@temparray);
my $newkey = join(" ", @temparray);
if (defined @newrows{$newkey}) {
for my $i (0..$#{ $rows{$key}}) {
$newrows{$newkey}->[$i] += $rows{$key}->[$i] > 0 ? 1 : 0;
}
} else {
my @new_row;
for my $i (0..$#{ $rows{$key}}) {
push(@new_row, $rows{$key}->[$i] > 0 ? 1 : 0);
}
$newrows{$newkey} = [ @new_row ];
}
}
for my $key (keys %newrows) {
print "$key\t", join("\t", @{ $newrows{$key} }), "\n";
}
自我提醒:始终检查您的假设。事实证明,在我的数亿行输入中的某个地方,事实上,在应该有 url 编码空格的地方存在文字空间。找到它们花了一些时间,因为有数亿个正确的文字空间,但它们就在那里。
对不起各位!
我正在使用 proc_open
将一些文本通过管道传输到 perl 脚本以加快处理速度。文本包括 url 编码的字符串以及文字 space。当 url 编码的 space 出现在原始文本中时,它似乎在到达 perl 脚本时被解码为文字 space。在 perl 脚本中,我依赖文字 spaces 的定位,所以这些不需要的 spaces 弄乱了我的输出。
为什么会发生这种情况,是否有办法防止这种情况发生?
相关代码片段:
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
);
$cmd = "perl script.pl";
$process = proc_open($cmd, $descriptorspec, $pipes);
$output = "";
if (is_resource($process)) {
fwrite($pipes[0], $raw_string);
fclose($pipes[0]);
while (!feof($pipes[1])) {
$output .= fgets($pipes[1]);
}
fclose($pipes[1]);
proc_close($process);
}
一行原始文本输入看起来像这样:
key url\tvalue1\tvalue2\tvalue3
我或许可以通过转换输入的格式来避免这个问题,但出于各种不希望的原因,并且绕过了而不是解决了关键问题。
此外,我知道问题发生在 php 脚本和 perl 脚本之间的某处,因为我在将其写入 perl 之前立即检查了原始文本(带有 echo
)脚本 STDIN 管道,我直接在 url 编码的原始字符串上测试了我的 perl 脚本。
我现在在下面添加了 perl 脚本。它基本上可以归结为一个小型 map-reduce 作业。
use strict;
my %rows;
while(<STDIN>) {
chomp;
my @line = split(/\t/);
my $key = $line[0];
if (defined @rows{$key}) {
for my $i (1..$#line) {
$rows{$key}->[$i-1] += $line[$i];
}
} else {
my @new_row;
for my $i (1..$#line) {
push(@new_row, $line[$i]);
}
$rows{$key} = [ @new_row ];
}
}
my %newrows;
for my $key (keys %rows) {
my @temparray = split(/ /, $key);
pop(@temparray);
my $newkey = join(" ", @temparray);
if (defined @newrows{$newkey}) {
for my $i (0..$#{ $rows{$key}}) {
$newrows{$newkey}->[$i] += $rows{$key}->[$i] > 0 ? 1 : 0;
}
} else {
my @new_row;
for my $i (0..$#{ $rows{$key}}) {
push(@new_row, $rows{$key}->[$i] > 0 ? 1 : 0);
}
$newrows{$newkey} = [ @new_row ];
}
}
for my $key (keys %newrows) {
print "$key\t", join("\t", @{ $newrows{$key} }), "\n";
}
自我提醒:始终检查您的假设。事实证明,在我的数亿行输入中的某个地方,事实上,在应该有 url 编码空格的地方存在文字空间。找到它们花了一些时间,因为有数亿个正确的文字空间,但它们就在那里。
对不起各位!