2

次のようなファイルがあります。

SECTION1 id name  
 sub section1
 sub section2
SECTION2 id name  
 sub section3
 sub section4
 sub section6
SECTION1 id name  
 sub section7
 sub section8
SECTION3 id name  
 sub section9
 sub section10
 sub section11
 sub section12
SECTION2 id name  
 sub section13
 sub section14
SECTION1 id name  
 sub section15
 sub section16
SECTION3 id name  
 sub section17
 sub section18

このファイルをセクションごとに並べ替える必要があります。私が知っている唯一のことは、「SECTION1」、「SECTION2」、「SECTION3」があるということです。ソート後に期待される出力は次のとおりです。

SECTION1 id name  
 sub section1
 sub section2
SECTION1 id name  
 sub section7
 sub section8
SECTION1 id name  
 sub section15
 sub section16
SECTION2 id name  
 sub section3
 sub section4
 sub section6
SECTION2 id name  
 sub section13
 sub section14
SECTION3 id name  
 sub section9
 sub section10
 sub section11
 sub section12
SECTION3 id name  
 sub section17
 sub section18

perlで、またはgrep、sedなどのユーティリティを使用してこれを行う簡単な方法はありますか?

4

5 に答える 5

3

を使用するもう1つの方法perl

infileが質問の内容と次の内容を持っていると仮定しますscript.pl:

use warnings;
use strict;
use sort qw/stable/;

my ($section, @section);

while ( <> ) { 

    ## Save text if first line or when line doesn't begin with 'SECTION' word.
    if ( $. == 1 || $_ !~ m/\ASECTION\d+/ ) { 
        $section .= $_; 
        next unless eof;
    }   

    ## Save the text and the number of section.
    if ( $section =~ m/\ASECTION(\d+)/ ) { 
        push @section, [ $1, $section ];
        $section = q||;
    }   

    ## Begin to save next section.
    $section .= $_; 
}

## Print them sorted by section number.
for ( sort { $a->[0] <=> $b->[0] } @section ) { 
    printf qq|%s|, $_->[1];
}

次のように実行します。

perl script.pl infile

次の出力で:

SECTION1 id name  
 sub section1
 sub section2
SECTION1 id name  
 sub section7
 sub section8
SECTION1 id name  
 sub section15
 sub section16
SECTION2 id name  
 sub section3
 sub section4
 sub section6
SECTION2 id name  
 sub section13
 sub section14
SECTION3 id name  
 sub section9
 sub section10
 sub section11
 sub section12
SECTION3 id name  
 sub section17
 sub section18
于 2012-06-24T17:43:09.057 に答える
3

特別な並べ替えが必要なようです。Perl のデフォルトの並べ替えでは、数値を含む文字列を適切に並べ替えることができないため、並べ替える前に数値を抽出する必要があります。ビッグ データ セットの場合は、シュワルツ変換で最適化しました。

その基本的な要点は、最初にセクション番号、次にサブセクション番号を抽出し、最初にセクション番号でソートし、同数の場合はサブセクション番号でソートすることです。サブセクションの最初の番号のみが考慮されるため、それらの行は既にソートされていると想定されます。

ファイルで使用するには、単に に変更<DATA>してから<>実行します。

perl script.pl inputfile > outputfile

コード:

use strict;
use warnings;

local $/;           # read entire file
my $data = <DATA>;  # slurp input file into scalar
my @records = split /(?=^SECTION)/m, $data;  # split into records
my @sorted =    map  {  $_->[0] }
                sort {  $a->[1] <=> $b->[1] ||
                        $a->[2] <=> $b->[2] }  
                map   { getnum($_) } @records;   # Schwartzian transform sort
print @sorted;

sub getnum {    # extract section and subsection numbers
    my ($sec) = $_[0] =~ /SECTION(\d+)/;
    my ($sub) = $_[0] =~ /\n.*?(\d+)/;
    return [ $_[0], $sec, $sub ];    # return anonymous array
}

__DATA__
SECTION1 id name  
 sub section1
 sub section2
SECTION2 id name  
 sub section3
 sub section4
 sub section6
SECTION1 id name  
 sub section7
 sub section8
SECTION3 id name  
 sub section9
 sub section10
 sub section11
 sub section12
SECTION2 id name  
 sub section13
 sub section14
SECTION1 id name  
 sub section15
 sub section16
SECTION3 id name  
 sub section17
 sub section18
于 2012-06-24T18:29:38.333 に答える
1

これは、セクションラベルに従って3つの個別のリストにレコードを蓄積することによって非常に簡単に実行されます。

このプログラムはハッシュを使用してこれを行い、ファイルの各行を最新のレコードに追加することで完全なセクションを作成します。行が新しいセクションの先頭である場合、行が追加される前に別の空のレコードがリストに追加されます。

結果を表示するには、リストのすべての要素をセクションラベルの順に印刷するだけです。

use strict;
use warnings;

open my $fh, '<', 'sections.txt' or die $!;

my %sections;
my $current_list;

while (<$fh>) {
  if (/^(SECTION[123])/) {
    $current_list = $sections{$1} //= [];
    push @$current_list, '';
  }
  $current_list->[-1] .= $_ if $current_list;
}

for my $name (sort keys %sections) {
  print for @{ $sections{$name} };
}

出力

SECTION1 id name  
 sub section1
 sub section2
SECTION1 id name  
 sub section7
 sub section8
SECTION1 id name  
 sub section15
 sub section16
SECTION2 id name  
 sub section3
 sub section4
 sub section6
SECTION2 id name  
 sub section13
 sub section14
SECTION3 id name  
 sub section9
 sub section10
 sub section11
 sub section12
SECTION3 id name  
 sub section17
 sub section18
于 2012-06-24T19:52:56.143 に答える
1
#!/usr/bin/perl
use strict;
use warnings;

my @data;
{   # limit change to $/ to this scope
    local $/ = "SECTION";
    @data = map {chomp; $_ || ()} <DATA>;   
}

{   # limit change to 'warnings' to this scope
    no warnings 'numeric';
    print "SECTION$_" for sort {$a <=> $b} @data;
}

これにより、個々のセクションが保持されます。

またはコマンドラインから:

perl -F/SECTION/ -0ane "print qq{SECTION$_} for grep $_, sort {$a <=> $b} @F" o33.txt
于 2012-06-24T17:46:54.537 に答える
1

これはうまくいくかもしれません(GNU sed):

sed ':a;$!N;/\nSECTION/!s/\n/\x00/;ta;s/n\([0-9][\x00\n]\|$\)/n0\1/g;P;D' file |
sort |
sed 's/\x00/\n/g;s/n0/n/g'

説明:

  • SECTIONssub sectionsを 1 行に結合します。:a;$!N;/\nSECTION/!s/\n/\x00/;ta
  • 0to を先頭に追加しsub sectionsます。s/n\([0-9][\x00\n]\|$\)/n0\1/g
  • 各行を印刷してから削除します。P;D
  • パイプ出力をソートします。sort
  • ソートされた出力を分解します。sed 's/\x00/\n/g;s/n0/n/g'
于 2012-06-24T17:55:54.090 に答える