我遇到的主要问题是我的脚本运行,打开文本文件,查找字符串,并将其复制到新文件,但有时它不会复制整个行。它在线路的不同点被切断。我相信我的正则表达式存在问题。
一行txt可能如下所示:
E03020039:无法将C:\ Documents and Settings \ rja07 \ Desktop \ DSMProduct \ project \ Database \ Schema \ Source \ MDB_data_type.dsm加载到\ DSM R17 \ projects \ Databases \ Schema \ Source \ MDB_data_type.dsm中。文本文件包含无效字符。
但是,当Perl脚本运行时,它有时只会复制到“文本文件”或“文本文件包含”字样,并且该行的最后部分被截断。我需要完整的一行。这就是我到目前为止所做的:
if ($error =~ /E03020039/)
{
print $error;
open (MF, '>>G:/perl/error.txt');
print MF $error;
$count ++;
}
对于扫描文件每一行的每个循环,这都在一个内部:
我试过了:
if ($error =~ /E03020039/&&/characters\s\.\n/)
但这对我没有任何帮助。
答案 0 :(得分:8)
在我们等待您提供的信息brian d foy时,我们应该检查一些可能的事情。
为什么?
好吧,看看你发布的代码片段,至少在风格方面,你似乎使用了一些更传统的Perlism,而不是现代改进的Perlisms,而现代方式做事通常会让你的生活更轻松。
use strict;
use warnings;
代码顶部的这两行可以帮助指出许多愚蠢的错误。
如果由于错误太多而无法在任何地方打开它们,您可以在范围内执行它们,即:
blah; #no strict or warnings
{ # scope
use strict;
use warnings;
code(); # with strict and warnings
}
blah; # no strict or warnings
裸露的文件句柄不整洁,因为它们是全球唯一的,这可能会有点混乱。
{ #scope
open my $fh , '>' , 'bar.txt';
print $fh "Hello\n";
} # file cleaned up and closed by perl!
好:
open my $fh, '>', 'bar.txt';
open my $otherfh, '<', 'foo.txt';
open my $iofh , '-|' , 'ls', '-la' ;
不推荐:
open my $fh, '>bar.txt';
open my $otherfh , '<foo.txt';
open my $iofh , 'ls -la |';
有关详细信息,请参阅perldoc -f open
一般情况下,如果因任何原因而开放死亡,默认行为是继续卡车运输,这可能有点奇怪。
有几种方法可以解决这个问题:
选项1:
use Carp();
open my $fh , '>', $filename or Carp::croak("Oh no! cant open $filename , $! $@");
选项2:
use autodie;
open my $fh , '>', $filename;
多数民众赞成可能没有按照你的想法去做。
if ($error =~ /E03020039/&&/characters\s\.\n/)
与
基本相同 if (
( $error =~ /E03020039/ )
&& ( $_ =~ /characters\s\.\n/ )
)
这可能不是你想要的。
我认为你的意思是:
if (
( $error =~ /E03020039/ )
&& ( $error =~ /characters\s\.\n/)
)
答案 1 :(得分:2)
我不认为你的正则表达式与此有任何关系。您是否至少在新文件中获得了所有正确的行,即使它们被截断了?
我认为您需要完成正常的调试步骤:
您能告诉我们一个完整但极少的程序来演示错误吗?问题可能出在其他地方。
什么是$ error?当你将它打印到标准输出时它是否具有所有的线?如果没有,请向后工作,直到找到文本丢失的位置。在可疑操作之前和之后打印其值,然后向后工作,直到找到问题为止。
您确定所有文字都在一行上,或者文件中没有任何额外的奇怪字符?下一行读取的错误是什么?
如果您将所有内容打印到新文件(即匹配所有行)会发生什么?所有文本是否都以新文件结尾?
这些行是否总是在同一点被截断?
答案 2 :(得分:0)
如果使用匹配模式(//与m //相同),则〜=运算符不应修改错误字符串。
在正则表达式检查之前,您是否100%确信自己没有将其破坏?我会在比赛前贴上一条打印线,确保你准确地复制输入。
您是否100%确信自己没有遇到IO缓冲问题?通常perl文件IO是缓冲的,所以如果你期望通过tail -f看到日志文件的完整,最后一行,你可能会在程序退出之前失望。
有关如何为文件句柄启用自动刷新的一些选项,请参阅http://www.rocketaware.com/perl/perlfaq5/How_do_I_flush_unbuffer_a_fileha.htm。
答案 3 :(得分:0)
如果只是为了完成工作 - 而不是学习如何在Perl中编程 - 那么使用'grep
'来找到这些行。这也假设你在脚本中没有做任何其他事情。如果打算了解Perl,那么你会忽略这个建议并注意其他答案。
答案 4 :(得分:-1)
我看到一些事情立即脱颖而出:
对于1和2:
# For loop around this:
if ($error =~ /E03020039/) {
print $error;
open(my $mf, '>>', 'G:/perl/error.txt')
or die "Unable to open error file - $!\n";
print $mf $error;
$count ++;
close $mf
or die "Unable to close error file - $!\n";
}
通过使用词法句柄,您可以防止任何其他代码在未明确传递的情况下触摸您的句柄。通过关闭句柄,可以刷新句柄的缓冲区。通过检查打开和关闭句柄的错误,可以防止未捕获的错误导致数据丢失。
您可能希望在for循环外移动打开和关闭:
my $count = 0;
open( my $mh, '>>', 'errorlog.log' ) or die "oops $!\n";
for my $error ( <$log_h> ) {
if ( $error =~ /E23323232323/ ) {
print $mh $error;
print $error;
$count++;
}
}
close $mh or die "oops $!\n";
您的代码正在重新打开同一个文件到全局文件句柄中。这可能很容易成为您所看到的问题的原因。它可能不是。错误的正确信息是否打印到STDOUT?
关于问题3,$error =~ /E03020039/&&/characters\s\.\n/
相当于:
($error =~ /E03020039/) && ($_ =~ /characters\s\.\n/)
如果您启用了警告,则可能(可能)收到Use of uninitialized value in pattern match (m//)
错误消息。这可能是令人惊讶的,但这可能是一个错误的线索。
我相信你想要的东西:
$ error =〜/ E03020039。*?characters \ s。$ /
但是没有理由扩展比赛,因为你没有捕捉到比赛的任何部分。它对$error
中的值或将写入文件的内容没有影响。
除非您有特殊原因,否则请始终使用以下两个pragma启动您的perl程序:
use strict;
use warnings;
即使你有充分的理由不使用它们,最好只在有限的范围内禁用这些pragma:
use strict;
use warnings;
{ no warnings 'uninitialized';
no strict 'vars';
print "$foo\n";
}
答案 5 :(得分:-1)
你的正则表达没问题。
还有其他两个问题:
open (MF, '>>G:/perl/error.txt');
附加到error.txt。因此,如果此脚本的多个实例并行运行,如果所有这些实例都尝试同时写入该文件,则可能会导致输出出现问题。或者你可以使用这个简单的Perl单线程,它可以达到你想要的目的:
perl -nle 'print if /E03020039/' inputFile.txt >> G:/perl/error.txt