我的工作对需要用户输入两个文件名的程序。 不幸的是,如果用户不按照输入的指定格式的程序可以轻松打破。 我想写的是提高了其对这些类型的错误代码的弹性。 当你看到我的代码,你会明白:
# Ask the user for the filename of the qseq file and barcode.txt file
print "Please enter the name of the qseq file and the barcode file separated by a comma:";
# user should enter filenames like this: sample1.qseq, barcode.txt
# remove the newline from the qseq filename
chomp ($filenames = <STDIN>);
# an empty array
my @filenames;
# remove the ',' and put the files into an array separated by spaces; indexes the files
push @filename, join(' ', split(',', $filenames))
# the qseq file
my $qseq_filename = shift @filenames;
# the barcode file.
my barcode = shift @filenames;
显然,如果用户输入错误类型的文件名(.tab文件,而不是.txt或.SEQ代替.qseq)运行此代码可以运行到错误。 我想代码,可以做一些检查,看看是在用户输入相应的文件类型。
如果用户输入文件名之前太多的空间,可能会破坏代码另一个错误是。 例如:sample1.qseq,(想象这里6位)barcode.txt(注意逗号后的众多空格)
又如:(想象这里6位)sample1.qseq,barcode.txt(此时间通知空间的第一个文件名前面的数字)
我也想的代码,可以去除多余的空格,使程序不破线。 我认为,用户输入必须是以下一种格式:sample1.qseq,barcode.txt。 用户输入必须是这种格式,这样我可以正确索引文件名到一个数组和后移位出来。
感谢任何帮助或建议,非常感谢!
对付这类问题的标准方式是使用命令行选项,而不是从STDIN收集输入。 getopt的::龙自带的Perl和是servicable:
use strict; use warnings FATAL => 'all';
use Getopt::Long qw(GetOptions);
my %opt;
GetOptions(\%opt, 'qseq=s', 'barcode=s') or die;
die <<"USAGE" unless exists $opt{qseq} and $opt{qseq} =~ /^sample\d[.]qseq$/ and exists $opt{barcode} and $opt{barcode} =~ /^barcode.*\.txt$/;
Usage: $0 --qseq sample1.qseq --barcode barcode.txt
$0 -q sample1.qseq -b barcode.txt
USAGE
printf "q==<%s> b==<%s>\n", $opt{qseq}, $opt{barcode};
外壳将处理任何多余的空白,尝试一下,看看。 你需要做的文件名的验证,我做了的例子正则表达式的东西。 采用波德::用法为输出有用的文档给用户谁都有可能获得调用错误的一个华丽的方式。
有几十个CPAN上更先进的Getopt模块。
首先,将use strict;
在你的代码的顶部,并声明变量。
其次,这样的:
# remove the ',' and put the files into an array separated by spaces; indexes the files
push @filename, join(' ', split(',', $filenames))
是不会做你想做的。 分裂()接受一个字符串并将其变为一个数组。 加入需要的项目清单,并返回一个字符串。 你只是想分裂:
my @filenames = split(',', $filenames);
像你期望这将创建一个数组。
此功能将安全地修剪掉一个字符串的开头和结尾的空白:
sub trim {
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
进入这样的:
my $file = trim(shift @filenames);
根据你的脚本,它可能是更容易通过字符串作为命令行参数。 你可以通过@ARGV数组访问他们,但我更喜欢使用getopt的::长:
use strict;
use Getopt::Long;
Getopt::Long::Configure("bundling");
my ($qseq_filename, $barcode);
GetOptions (
'q|qseq=s' => \$qseq_filename,
'b|bar=s' => \$barcode,
);
然后,您可以拨打此为:
./script.pl -q sample1.qseq -b barcode.txt
和变量将被正确填充,而不需要担心修剪空白。
你需要修剪在你的日常处理文件名数据之前的空间,你可以用另一种正则表达式检查文件的扩展名,如描述很好有在Perl的正则表达式来查找文件的扩展名? 。 如果它是对你很重要文件的实际类型,那么它可能是更欢颜用,而不是检查该文件:: LibMagicType 。
虽然我觉得你的设计是有点玄乎,下面的工作?
my @fileNames = split(',', $filenames);
foreach my $fileName (@fileNames) {
if($fileName =~ /\s/) {
print STDERR "Invalid filename.";
exit -1;
}
}
my ($qsec, $barcode) = @fileNames;
这里是另一种方式,你可以用正则表达式做(如果你正在阅读从输入STDIN
):
# read a line from STDIN
my $filenames = <STDIN>;
# parse the line with a regex or die with an error message
my ($qseq_filename, $barcode) = $filenames =~ /^\s*(\S.*?)\s*,\s*(\S.*?)\s*$/
or die "invalid input '$filenames'";