2009-12-12 21 views
9

Programlama benim için çok yeni, soruyu nasıl ifade edeceğimi bilmediğim için özür dilerim.Perl'de sabit genişlikli sütunları nasıl ayırabilirim?

Dahili bir araçtan bir değişken alan bir Perl betiğim var. Göründüğü gibi değil her zaman, ama her zaman bu model takip edecek: Perl ile

darren.local   1987 A  Sentence1 
darren.local   1996 C  Sentence2 
darren.local   1991 E  Sentence3 
darren.local   1954 G  Sentence4 
darren.local   1998 H  Sentence5 

, tek başına bir değişkene bu satırların her biri almanın en kolay yolu nedir? Dahili aracın her satıra ne tükettiğine bağlı olarak her zaman farklı olacak ve beş satırdan fazla olabilir. Her satırdaki büyük harf, sonuna kadar sıralanacaktır (tümü gibi tüm Cs, tüm Es, vb.). Normal ifadelere bakmalı mıyım? Böyle metin şey her satırı için

+0

Bu veriler/satırlar nerede? Dahili aracınız bunları tek bir değişkene mi koyuyor? Yoksa bu metin verileri okumak için gereken bir dosyada mı? –

+0

Araç bunları tek bir değişkene yerleştirir. – scraft3613

+0

Perl newbies var! 1 – nes1983

cevap

17

Bu tür bir şey için unpack kullanmayı seviyorum. Hızlı, esnek ve geri dönüşümlüdür.

Her sütunun konumlarını bilmeniz yeterlidir ve unpack her bir sütundan ek boşlukları otomatik olarak kırpabilir. Eğer sütunlardan birinin bir şey değiştirirseniz

, aynı formatı ile yeniden ambalajlama orjinal biçimine paketi gitmek kolaydır:

my $format = 'A23 A8 A7 A*'; 

while(<DATA>) { 
    chomp(my $line = $_); 

    my($machine, $year, $letter, $sentence) = 
     unpack($format, $_); 

    # save the original line too, which might be useful later 
    push @grades, [ $machine, $year, $letter, $sentence, $_ ]; 
    } 

my @sorted = sort { $a->[2] cmp $b->[2] } @grades; 

foreach my $tuple (@sorted) { 
    print $tuple->[-1]; 
    } 

# go the other way, especially if you changed things 
foreach my $tuple (@sorted) { 
    print pack($format, @$tuple[0..3]), "\n"; 
    } 

__END__ 
darren.local   1987 A  Sentence1 
darren.local   1996 C  Sentence2 
darren.local   1991 E  Sentence3 
darren.local   1954 G  Sentence4 
darren.local   1998 H  Sentence5 

Şimdi, ilave bir husus var. Tek bir değişkende bu çok satırlı çok satırlı bir metne sahip olabileceğinize benziyor. Scalar'a bir referansta bir dosya işleci açarak bunu bir dosya olarak ele alın. bundan daha basit olsun yok

my $lines = '...multiline string...'; 

open my($fh), '<', \ $lines; 

while(<$fh>) { 
     ... same as before ... 
     } 
+1

Bir 'A23 A8 A7 A *' 'biçimi de işe yarayacak. –

+3

Güzel bir okunabilir Perl ... örneği (her iki yılda bir kullanıcı için bile) – Rook

+0

Gönderdiğim ilk formatta bir hata yaptığım için hangi biçimi gördüğünüzden emin değilim, ama bitti aynı formatta. –

3
use strict; 
use warnings; 

# this puts each line in the array @lines 
my @lines = <DATA>; # <DATA> is a special filehandle that treats 
        # everything after __END__ as if it was a file 
        # It's handy for testing things 

# Iterate over the array of lines and for each iteration 
# put that line into the variable $line 
foreach my $line (@lines) { 
    # Use split to 'split' each $line with the regular expression /s+/ 
    # /s+/ means match one or more white spaces. 
    # the 4 means that all whitespaces after the 4:th will be ignored 
    # as a separator and be included in $col4 
    my ($col1, $col2, $col3, $col4) = split(/\s+/, $line, 4); 

    # here you can do whatever you need to with the data 
    # in the columns. I just print them out 
    print "$col1, $col2, $col3, $col4 \n"; 
} 


__END__ 
darren.local   1987 A  Sentece1 
darren.local   1996 C  Sentece2 
darren.local   1991 E  Sentece3 
darren.local   1954 G  Sentece4 
darren.local   1998 H  Sentece5 
0

:

my ($domain, $year, $grade, @text) = split /\s+/, $line; 

açık değil çünkü sonunda cümle boşluk veya etmezse ben cümle için bir dizi kullanın. Daha sonra gerekirse @text dizisine yeni bir dizeye katılabilirsiniz. Sonundaki cümleler boşluk bırakmayacaksa, $ metnine @text dönüştürebilirsiniz. Metin tek bir değişken $ bilgi konur varsayarsak

+0

ile bölüneceğini unutmayın. Bu durumda split kullanacaksanız, döndürdüğü öğe sayısını sınırlamak için üçüncü argümanı kullanın. Son sütun önemli boşluk içeriyorsa, verilerin bir kısmını kaybedersiniz. –

2

, o zaman içsel perl bölünmüş işlevini kullanarak ayrı satırlara içine ayırabilirsiniz: @lines Çizgilerinizin bir dizidir

my @lines = split("\n", $info); 

. "\ N", bir satırsonunun normal ifadesidir. Her hat üzerinden döngü aşağıdaki gibi: Bu durumda, boşluk her satırı bölmek için

foreach (@lines) { 
    $line = $_; 
    # do something with $line.... 
} 

(\ ın bir boşluk karakteri normal ifade \ s +, anlamına gelir ve + 1 ya da daha fazla kez):

@fields = split("\s+", $line); 

ve daha sonra onun dizi indeksi üzerinden doğrudan her alanı erişebilirsiniz: $ alan [0], $ alan [1] vb

ya, bunu yapabilirsiniz:

($var1, $var2, $var3, $var4) = split("\s+", $line); 

, her satırdaki alanları ayrı ayrı adlandırılmış değişkenlere koyar.

Şimdi - Eğer tür istiyorsanız üçüncü sütunda karakteri ederek hatları, bunu yapabilirdi:

my @lines = split("\n", $info); 
my @arr =(); # declare new array 

foreach (@lines) { 
    my @fields = split("\s+", $_); 
    push(@arr, \@fields) # add @fields REFERENCE to @arr 
} 

Artık bir "Dizilerin dizisi" var.

@sorted = sort { $a->[2] <=> $b->[2] } @arr; 

3 elemanın @fields arasında (endeks 2) tarafından @arr sıralamak hangi şöyledir: Bu kolayca sıralanabilir.

kendi değişkenlere aynı üçüncü sütun ile satırları koymak için Düzen 2 Bunu yapmak: Artık

my %hash =();    # declare new hash 

foreach $line (@arr) {  # loop through lines 
    my @fields = @$line;  # deference the field array 

    my $el = $fields[2];  # get our key - the character in the third column 

    my $val = ""; 
    if (exists $hash { $el }) {   # check if key already in hash 
    my $val = $hash{ $el };  # get the current value for key 
    $val = $val . "\n" . $line; # append new line to hash value   
    } else { 
    $val = $line; 
    } 
    $hash{ $el } = $val;   # put the new value (back) into the hash 
} 

sahip olduğunuz her tuş varlık için değer ile, üçüncü sütunda karakterleri ile anahtarlı bir karma Bu anahtarı içeren satırlar. Daha sonra karma yoldan geçebilir ve çıktı alabilir veya karma değerler kullanabilirsiniz.

+0

Bu durumda bölme kullanacaksanız, döndürdüğü öğelerin sayısını sınırlamak için üçüncü bağımsız değişkeni kullanın. Son sütun önemli boşluk içeriyorsa, verilerin bir kısmını kaybedersiniz. –

+0

Teşekkürler Richard - her satırın büyük harflerle gruplanması gerekir. Bu sorgu çıktısına bağlı olarak, 20 satır veya 2 satır kadar az olabilir. "C" satırlarının bir değişkene girmesi gerekiyor, "B" satırları kendi değişkenlerine girmeye ihtiyaç duyuyor, vb. Bu işe yaramayacak mı? Yukarıdaki yanıtımdaki sıralama işlevini kullanarak – scraft3613

+0

, diziniz alfasayısal olarak sıralanacaktır. İlk önce "A" lar görünecek, "B" den sonra gelecek. Tüm "A" satırlarını tek bir değişkene koymak isterseniz, (herhangi bir programlama problemi gibi) bir dizi olasılık vardır. Anahtarlı bir hash/haritayı, anahtarınız olarak "A" vb. Karakterlerle kullanabilirsiniz. Değer, a) bir dizi satır veya b) onları bulduğunuz sırada sonraki satırları eklediğiniz tek bir değerdir. Karma kullanımıyla ilgili bir eğitim için bkz. here. –

-1

Kullanım CPAN ve benim modülü DataExtract::FixedWidth

#!/usr/bin/env perl 
use strict; 
use warnings; 
use DataExtract::FixedWidth; 

my @rows = <DATA>; 

my $defw = DataExtract::FixedWidth->new({ heuristic => \@rows, header_row => undef }); 

use Data::Dumper; 

print Dumper $defw->parse($_) for @rows; 

__DATA__ 
darren.local   1987 A  Sentence1 
darren.local   1996 C  Sentence2 
darren.local   1991 E  Sentence3 
darren.local   1954 G  Sentence4 
darren.local   1998 H  Sentence5 

: dt şeyler gerisini halleder.

İlgili konular