正则表达式:如何删除Perl中字符串之间的额外空格

时间:2012-06-09 01:30:31

标签: regex perl user-input filehandle removing-whitespace

我正在开发一个程序,它接受两个文件名的用户输入。不幸的是,如果用户不遵循指定的输入格式,程序很容易中断。我想编写代码来提高它对这些类型的错误的弹性。当你看到我的代码时,你会明白的:

# 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。用户输入必须采用这种格式,以便我可以将文件名正确地索引到一个数组中,然后将它们移出。

感谢任何帮助或建议,我们非常感谢!

5 个答案:

答案 0 :(得分:8)

处理此类问题的标准方法是使用命令行选项,而不是从STDIN收集输入。 Getopt::Long附带Perl并且可以使用:

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};

shell将处理任何无关的空白,尝试并查看。您需要对文件名进行验证,我在示例中使用了正则表达式。使用Pod::Usage以更好的方式将有用的文档输出给可能导致调用错误的用户。

CPAN上有许多更先进的Getopt模块。

答案 1 :(得分:4)

首先,将use strict;放在代码顶部并声明变量。

第二,这:

# remove the ',' and put the files into an array separated by spaces; indexes the files
push @filename, join(' ', split(',', $filenames))

不会做你想做的事。 split()接受一个字符串并将其转换为数组。 Join获取项目列表并返回一个字符串。你只想分开:

my @filenames = split(',', $filenames);

这将创建一个你期望的数组。

此函数将安全地从字符串的开头和结尾修剪空白区域:

sub trim {
    my $string = shift;
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
}

像这样访问它:

my $file = trim(shift @filenames);

根据您的脚本,将字符串作为命令行参数传递可能更容易。您可以通过@ARGV数组访问它们,但我更喜欢使用GetOpt :: Long:

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

并且可以正确填充变量,而无需担心修剪空白区域。

答案 2 :(得分:2)

在处理例程中的文件名数据之前,您需要trim个空格,您可以使用另一个正则表达式检查文件扩展名,如Is there a regular expression in Perl to find a file's extension?中所述。如果它是对您来说重要的实际文件类型,那么使用File::LibMagicType来检查它可能更值得。

答案 3 :(得分:1)

虽然我认为您的设计有点不确定,但以下内容会有效吗?

my @fileNames = split(',', $filenames);
foreach my $fileName (@fileNames) {
  if($fileName =~ /\s/) {
    print STDERR "Invalid filename.";
    exit -1;
  }
}
my ($qsec, $barcode) = @fileNames;

答案 4 :(得分:1)

以下是另一种使用正则表达式的方法(如果您正在阅读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'";