为什么'chomp'无法使用Eclipse和Cygwin Perl删除Windows XP上的换行符?

时间:2009-10-05 06:30:53

标签: perl

我正在运行Windows XP,带有EPIC的Eclipse 3.2和用于我的Perl解释器的Cygwin,我得到了意想不到的结果。

仅供参考...当我在我的Ubuntu发行版(VMware,同一台电脑上)上运行时,我得到了预期的结果。为什么呢?

############ CODE: #############

use warnings;
use strict;

my $test = "test";
my $input = <STDIN>;

print length $test, " ", length $input, "\n";

chomp $input;

print "|$test| |$input| \n";    #The bars indicate white space, new line, etc...

print length $test, " ", length $input, "\n";

if ($test eq $input) {
    print "TIME TO QUIT";
}

Windows XP上的结果:

test           <-- My input
4 6            <-- Lengths printed before chomp
|test| |test   <-- Print the variables after chomp
|              <-- There is still a new line there
4 5            <-- Lengths after the initial chomp

3 个答案:

答案 0 :(得分:6)

鉴于Windows XP在问题中的数字,差异必须归因于CRLF(回车,换行)处理。 chomp删除LF,但不删除CR;打印将CR转换为CR LF。

chomp的Perl文档说,如果您为Windows($/ = "\r\n";)正确设置EOL,那么chomp应该正确地执行其操作:

$/ = "\r\n";
$test = "test\r\n";
print "<<$test>>\n";
chomp $test;
print "<<$test>>\n";

输出的十六进制转储产生:

0x0000: 3C 3C 74 65 73 74 0D 0A 3E 3E 0A 3C 3C 74 65 73   <<test..>>.<<tes
0x0010: 74 3E 3E 0A                                       t>>.
0x0014:

我不确定为什么$/没有自动设置 - 可能是Cygwin混淆了事情(假装太成功,它在Unix上运行)。

答案 1 :(得分:4)

根据长度,我会说你输入的字符串为:

test<cr><lf>

其中<cr><lf>分别是ASCII码0x13和0x10。

当你选择它时,会删除<lf>,但会将<cr>留在那里。

这几乎可以肯定是Eclipse,Cygwin和Windows之间的交互问题,不同意行尾字符序列应该是什么。我无法使用Perl / Cygwin Perl / Windows复制您的问题,但此命令会产生类似的结果(在Cygwin中):

echo 'test^M' | perl qq.pl | sed 's/^M/\n/g'

qq.pl是您的脚本,"^M"是实际的CTRL-M)。这是文本形式的输出:

4 6
|test| |test
|
4 5

和八进制转储:

0000000 2034 0a36 747c 7365 7c74 7c20 6574 7473
          4       6  \n   |   t   e   s   t   |       |   t   e   s   t
        064 040 066 012 174 164 145 163 164 174 040 174 164 145 163 164
0000020 7c0a 340a 3520 000a
         \n   |  \n   4       5  \n  \0
        012 174 012 064 040 065 012 000
0000027

所以我要说你的输入同时放在<cr> <lf>上,并且打印件正在将<cr>翻译为<lf> (或者只对两者做同样的事情)。

如果您需要针对您的环境采取解决方法,可以将chomp行替换为:

$input =~ s/\r?\n$//;

如:

use warnings;
use strict;
my $test = "test";
my $input = <STDIN>;
print length $test ," ",length $input,"\n";
$input =~ s/\r?\n$//;
print "|$test| |$input|\n";
print length $test," ",length $input,"\n";
if ($test eq $input) {
    print "TIME TO QUIT";
}

对我使用的测试数据在Cygwin上工作(当然,检查它自己的情况),但是你可能会发现你可以通过使用所有在行结束序列上达成一致的工具来更好地解决它(例如,Perl for Windows而不是Cygwin可以帮你解决问题。)

答案 2 :(得分:4)

以下是如何移除尾随的\r\n\n(以最后者为准):

$input =~ s@\r?\n\Z(?!\n)@@;

另一个选择是做一个

binmode(STDIN, ':crlf')

从STDIN读取任何内容之前。这会将尾随\r\n转换为\n,您可以使用chomp将其删除。即使您的输入仅包含\n,这也会起作用。有关更多信息,请参阅有关PerlIO的文档。