2012-06-09 13 views
6

Pracuję nad programem, który pobiera dane użytkownika dla dwóch nazw plików. Niestety program może się łatwo zepsuć, jeśli użytkownik nie zastosuje się do określonego formatu danych wejściowych. Chcę napisać kod, który poprawia jego odporność na tego typu błędy. Zrozumiesz, gdy widzisz mój kod:Regex: Jak usunąć dodatkowe spacje między ciągami w Perlu

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

Oczywiście kod jest uruchamiany może napotkasz błędy, jeśli użytkownik wpisze niewłaściwy typ pliku (plik .tab zamiast .txt lub .seq zamiast .qseq) . Chcę kod, który może wykonać pewien rodzaj sprawdzenia, aby zobaczyć, że użytkownik wprowadza odpowiedni typ pliku.

Innym błędem, który może złamać kod, jest sytuacja, w której użytkownik wprowadzi zbyt wiele spacji przed nazwami plików. Na przykład: sample1.qseq, (wyobrazić sobie 6 spacji) barcode.txt (Zwróć uwagę na spacje po przecinku)

Inny przykład: (proszę wyobrazić sobie 6 miejsc) sample1.qseq, barcode.txt (tym razem liczba spacji przed pierwszą nazwą pliku)

Chcę również linii kodu, który może usunąć dodatkowe spacje, aby program się nie zepsuł. Myślę, że dane wejściowe użytkownika muszą mieć następujący format: sample1.qseq, barcode.txt. Dane wejściowe użytkownika muszą być w tym formacie, aby poprawnie indeksować nazwy plików w tablicy i później je przenosić.

Dzięki za pomoc lub sugestie są bardzo mile widziane!

+0

zapomniałem wspomnieć: Jest to tylko jeden z sześciu skryptów muszę modyfikować dla potokowego uruchomienia w linii poleceń. Innymi słowy, chcę, aby uruchomiona instalacja działała jak: Script00.pl | Script01.pl | Script02.pl | Script03.pl | Script04.pl | Script05.pl | Script06.pl. To jest pierwszy skrypt w rurze – cooldood3490

Odpowiedz

8

Standardowym sposobem radzenia sobie z tego rodzaju problemu jest wykorzystanie opcji wiersza polecenia, nie gromadząc dane wejściowe z stdin. Getopt::Long pochodzi z Perl i 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}; 

Skorupa zajmie się każdym obcego spacją, spróbować i zobaczyć. Musisz wykonać sprawdzanie poprawności nazw plików, w przykładzie wymyśliłem coś z regex. Zatrudnij Pod::Usage, aby uzyskać lepszy sposób dostarczania pomocnej dokumentacji użytkownikom, którzy mogą błędnie wywołać inwokację.

Istnieją dziesiątki bardziej zaawansowanych modułów Getopt na CPAN.

+0

dzięki daxim! wydaje się, że korzystanie z opcji wiersza polecenia z Getopt :: Long jest drogą do zrobienia. Dodatkowo wygląda na to, że nawet sprawdzisz, czy nazwa pliku jest poprawna. dziękuję, sam bym się nie zorientował. Czy możesz szybko wyjaśnić, w jaki sposób działa każda linia kodu? Z * prawie * rocznym doświadczeniem, wciąż jestem stosunkowo początkującym programistą Perla. Widzę, że przechowujesz nazwy plików w hash% opt. Ale czy możesz wyjaśnić, w jaki sposób działa bit regex i UŻYJ i inne części? Przyjrzę się modułowi Getopt :: Long. – cooldood3490

+0

Czy uważasz, że ten moduł będzie działał dla całego rodzaju projektu, nad którym pracuję? Widzisz, jest to tylko jeden z sześciu skryptów, które muszę zmodyfikować, aby uruchomić przebieg w linii poleceń. Innymi słowy, chcę, aby uruchomiona instalacja działała jak: Script00.pl | Script01.pl | Script02.pl | Script03.pl | Script04.pl | Script05.pl | Script06.pl. wszelkie uwagi uzupełniające są bardzo mile widziane. – cooldood3490

+0

Polecenia rurociągu działają w całości na podstawie ich wyników. Zasadniczo wynik pierwszego polecenia musi być tym, czego potrzebujesz jako danych wejściowych dla następnego polecenia. – Ilion

2

Przed przetworzeniem danych pliku w swojej procedurze będziesz potrzebować trim spacji, możesz sprawdzić rozszerzenie pliku za pomocą innego wyrażenia regularnego, co jest dobrze opisane w Is there a regular expression in Perl to find a file's extension?. Jeśli chodzi o rzeczywisty typ pliku, który jest dla Ciebie ważny, może być bardziej godny zaufania, aby to sprawdzić zamiast tego z File::LibMagicType.

+0

@daxim dzięki za te świetne linki. dzięki za odpowiedź Harald – cooldood3490

4

Najpierw wstaw kod use strict; w górnej części kodu i zadeklaruj zmienne.

drugie, to:

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

nie zamierza robić, co chcesz. split() pobiera ciąg znaków i przekształca go w tablicę. Join pobiera listę pozycji i zwraca ciąg znaków. Po prostu chcesz podzielić:

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

To stworzy tablicę, jakiej oczekujesz.

Ta funkcja będzie bezpiecznie przyciąć białe znaki z początku i końca łańcucha:

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

dostęp to tak:

my $file = trim(shift @filenames); 

Zależnie od scenariusza, może łatwiej będzie przejść ciągi jako argumenty wiersza poleceń. Można uzyskać do nich dostęp za pośrednictwem tablicy @ARGV ale wolę używać 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, 
); 

Następnie można nazwać jako:

./script.pl -q sample1.qseq -b barcode.txt 

a zmienne zostaną prawidłowo wypełniona, bez konieczności martwić się przycięciem białej przestrzeni.

+0

dziękuję Llion za rewizję mojego kodu. Mogę użyć podanego podprogramu wykończenia. To powinno zająć się dowolną wiodącą lub ciągnącą się białą przestrzenią. zaproponowany przez Ciebie moduł GetOpt :: Long brzmi jak coś, czego potrzebuję, to tylko fragment całego projektu. Widzisz, jest to tylko jeden z sześciu skryptów, które muszę zmodyfikować, aby uruchomić przebieg w linii poleceń. Innymi słowy, chcę, aby uruchomiona instalacja działała jak: Script00.pl | Script01.pl | Script02.pl | Script03.pl | Script04.pl | Script05.pl | Script06.pl. Na pewno zobaczę, czy ten moduł działa dobrze. Jeszcze raz dziękuję – cooldood3490

1

Chociaż myślę, że Twój projekt jest trochę niepewny, poniższe będą działać?

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

To jednak nie odpowiada na pytanie. To po prostu pomyłki, gdy format jest nieoczekiwany. A co jeśli w nazwie pliku znajdują się spacje? – Ilion

+0

Tak, wyobrażam sobie, że coś takiego sprawi, że użytkownik będzie szybko sfrustrowany. Próbuję napisać kod przyjazny dla użytkownika. dobra sugestia. – cooldood3490

1

I tu jest jeszcze jeden sposób można zrobić to z regex (jeśli czytasz wejście od 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'"; 
Powiązane problemy