如何使用perl处理格式类似于unicode的文件?

如何使用perl处理格式类似于unicode的文件?,perl,file,encode,Perl,File,Encode,我有一个遗留程序,在运行它之后,它将生成一个日志文件。现在我需要分析这个日志文件 但是文件格式非常奇怪。请看下面,我用vi打开它,它看起来像一个unicode文件,但它不是FFFE启动的。使用记事本打开、保存并再次打开后,我发现FFFE是由记事本添加的。然后,我可以使用命令“type log.txt>log1.txt”将整个文件转换为ANSI格式。稍后在perl中,我可以使用/TDD/在perl中搜索我需要的内容 但是现在,我无法处理这种文件格式 如有任何意见或想法,将不胜感激 0000000:

我有一个遗留程序,在运行它之后,它将生成一个日志文件。现在我需要分析这个日志文件

但是文件格式非常奇怪。请看下面,我用vi打开它,它看起来像一个unicode文件,但它不是FFFE启动的。使用记事本打开、保存并再次打开后,我发现FFFE是由记事本添加的。然后,我可以使用命令“type log.txt>log1.txt”将整个文件转换为ANSI格式。稍后在perl中,我可以使用/TDD/在perl中搜索我需要的内容

但是现在,我无法处理这种文件格式

如有任何意见或想法,将不胜感激

0000000: 5400 4400 4400 3e00 2000 4c00 6f00 6100  T.D.D.>. .L.o.a.
在记事本之后保存它

0000000: fffe 5400 4400 4400 3e00 2000 4c00 6f00  ..T.D.D.>. .L.o.

open STDIN, "< log.txt";
while(<>)
{
  if (/TDD/)
  {
    # Add my logic.
  }
}
更新

我用命令尝试了UTF-16LE:

perl.exe open.pl utf-16le utf-16 <my log file>.txt
open.pl第18行

is "print while <$fh>;"
使用十六进制读取器打开它:

0000070: a88d e590 80e4 9080 e490 80e3 b880 e280  ................
0000080: 80e4 b080 e6bc 80e6 8480 e690 80e6 a480  ................
0000090: e6b8 80e6 9c80 e280 80e6 8c80 e68c 80e6  ................
00000a0: b480 e68c 80e6 bc80 e788 80e6 9480 e2b8  ................

您的文件似乎是用UTF-16LE编码的。记事本添加的字节称为“字节顺序标记”,或仅称为BOM

以下是如何使用Perl读取文件:

use strict;
use warnings;
use Encode;
# list loaded encodings
print STDERR map "* $_\n", Encode->encodings;
# read arguments
my $enc = shift || 'utf16';
die "no files :-(\n" unless @ARGV;
# process files
for ( @ARGV ) {
    open my $fh, "<:encoding($enc)", $_ or die "open $_: $!";
    print <$fh>;
    close $fh;
}
# loaded more encodings now
print STDERR map "* $_\n", Encode->encodings;
以下是tchrist建议的修订版本:

use strict;
use warnings;
use Encode;

# read arguments
my $enc_in  = shift || die 'pass file encoding as first parameter';
my $enc_out = shift || die 'pass STDOUT encoding as second parameter';
print STDERR "going to read files as encoded in: $enc_in\n";
print STDERR "going to write to standard output in: $enc_out\n";
die "no files :-(\n" unless @ARGV;

binmode STDOUT, ":encoding($enc_out)"; # latin1, cp1252, utf8, UTF-8

print STDERR map "* $_\n", Encode->encodings; # list loaded encodings

for ( @ARGV ) { # process files
    open my $fh, "<:encoding($enc_in)", $_ or die "open $_: $!";
    print while <$fh>;
    close $fh;
}

print STDERR map "* $_\n", Encode->encodings; # more encodings now
使用严格;
使用警告;
使用编码;
#读参数
my$enc|u in=shift | | die‘将文件编码作为第一个参数传递’;
my$enc|u out=shift | | die‘将标准输出编码作为第二个参数传递’;
打印STDERR“将读取编码为:$enc_in\n的文件”;
打印STDERR“将写入标准输出:$enc\u out\n”;
死“无文件:-(\n)”除非@ARGV;
binmode标准输出,“:编码($enc#u out)”;#拉丁1、cp1252、utf8、UTF-8
打印标准映射“*$\un”,编码->编码;#列出加载的编码
对于(@ARGV){#进程文件

打开我的$fh,“这可能会有所帮助:您是否尝试过为流读取指定不同的编码?您链接到的问题的公认答案准确地告诉您需要执行哪些操作才能读取UCS-2LE编码的文件。我刚刚尝试过,它对我有效。-请更具体地说明您“无法解决”的原因.Orionpax,不要发布后续问题作为答案。请阅读我尝试了不同的编码,包括UTF16-LE、UTF16-BE、UCS-2LE、UCS-2BE等,但我仍然得到了相同的错误****:open.pl第23行、第1824行的部分字符。谢谢Michael。我尝试了,但在test.pl第12行出现了类似于
UTF-16:unrecogned BOM 5400的错误在Perl中的
print;
@Orionpax上,
utf16
编码需要一个BOM表,因为它可以是大的或小的endian。尝试使用
UTF-16LE
。然后在没有BOM的文件上运行它。要更新我的示例。不要使用
print
,因为它在开始打印之前会吸收整个文件,这是我需要的s不可扩展。请在打印时使用
并确保您首先使用
binmode(STDOUT,“:utf8”)
或同等版本。@tchrist-谢谢,再次强调要点。将更新我的示例脚本。
tests.cpp:34)
਍吀䐀䐀㸀 䰀漀愀搀椀渀最 挀挀洀挀漀爀攀⸀搀氀
0000070: a88d e590 80e4 9080 e490 80e3 b880 e280  ................
0000080: 80e4 b080 e6bc 80e6 8480 e690 80e6 a480  ................
0000090: e6b8 80e6 9c80 e280 80e6 8c80 e68c 80e6  ................
00000a0: b480 e68c 80e6 bc80 e788 80e6 9480 e2b8  ................
use strict;
use warnings;
use Encode;
# list loaded encodings
print STDERR map "* $_\n", Encode->encodings;
# read arguments
my $enc = shift || 'utf16';
die "no files :-(\n" unless @ARGV;
# process files
for ( @ARGV ) {
    open my $fh, "<:encoding($enc)", $_ or die "open $_: $!";
    print <$fh>;
    close $fh;
}
# loaded more encodings now
print STDERR map "* $_\n", Encode->encodings;
perl open.pl utf16 open.utf16be.txt
perl open.pl utf16 open.utf16le.txt
perl open.pl utf16le open.utf16le.nobom.txt
use strict;
use warnings;
use Encode;

# read arguments
my $enc_in  = shift || die 'pass file encoding as first parameter';
my $enc_out = shift || die 'pass STDOUT encoding as second parameter';
print STDERR "going to read files as encoded in: $enc_in\n";
print STDERR "going to write to standard output in: $enc_out\n";
die "no files :-(\n" unless @ARGV;

binmode STDOUT, ":encoding($enc_out)"; # latin1, cp1252, utf8, UTF-8

print STDERR map "* $_\n", Encode->encodings; # list loaded encodings

for ( @ARGV ) { # process files
    open my $fh, "<:encoding($enc_in)", $_ or die "open $_: $!";
    print while <$fh>;
    close $fh;
}

print STDERR map "* $_\n", Encode->encodings; # more encodings now