複数のヘッダーで複数のファイルを関連付ける

複数のヘッダーで複数のファイルを関連付ける

たとえば、複数のヘッダーを持つ複数のファイルを、すべての情報を含む1つのファイルにリンクしたいとします。

ファイル1:

Numbers
1
2
3

Letters
A
B
C

ファイル2:

Numbers
4
5
6

Letters
D
E
F

ファイル3は、次のものをマージすることによって生成されます。

Numbers
1
2
3
4
5
6

Letters
A
B
C
D
E
F

これまでcatを試してfile2を最後に追加し、各ヘッダーの下のすべてのデータをgrepしようとしましたが、簡単に言えば失敗しました。

貼り付けようとしましたが、各ファイルのデータ量が等しい場合は、最後のファイルの横に[ファイル固有の情報]タブを追加するので、悪くはありませんが、あるファイルのヘッダーの下に他のファイルよりも多くの項目がある場合は混乱を招きます。

この種の問題を解決する方法を知っている人はいますか?

答え1

セクションキーワードの下に「====」があると仮定すると、次のPythonはセクション名を明示的に指定せずに問題を解決します。

import sys
from collections import OrderedDict

combined = OrderedDict()
seperator = '===='

for file_name in 'f1.txt f2.txt'.split(): #sys.argv[1:]:
    with open(file_name) as fp:
        lines = fp.readlines()
        data = []
        while len(lines):
            # reverse over the lines
            line = lines.pop(-1)
            if not line.strip(): continue # skip empty
            if line.startswith(seperator):
                name = lines.pop(-1)
                section = combined.setdefault(name, [])
                section.extend(reversed(data))
                data = []
            else:
                data.append(line)

for idx, k in enumerate(reversed(combined)):
    if idx != 0:
        print # insert empty line before all but first
    sys.stdout.write(k)
    print('=' * len(k))
    for line in combined[k]:
        sys.stdout.write(line)

コマンドラインを呼び出すときにファイル名を指定する必要があります。

これにより、次のような出力が生成されます。

Numbers
========
1
2
3
4
5
6

Letters
========
A
B
C
D
E
F

答え2

Perlスクリプトを使用してこれを行う1つの方法は次のとおりです。

#!/usr/bin/perl

my @fileInfo;
open(my $fh, "<file1");
push (@fileInfo,<$fh>);
close($fh);
open(my $fh, "<file2");
push (@fileInfo,<$fh>);
close($fh);

my @letLines;
my @numLines;
my $numMode  = 0;
my $letMode  = 0;

foreach my $line (@fileInfo) {

    # skip empty and '==' lines
    next if ($line =~ /^$/);
    next if ($line =~ /==/);

    if ($line =~ /Letters/) {
        $letMode = 1;
        $numMode = 0;
        next;
    }

    if ($line =~ /Numbers/) {
        $numMode = 1;
        $letMode = 0;
        next;
    }

    if ($letMode) {
        push (@letLines, $line);
        next;
    }

    if ($numMode) {
        push (@numLines, $line);
        next;
    }
}

print "Numbers\n";
print "=======\n";
print @numLines;

print "\n";

print "Letters\n";
print "=======\n";
print @letLines;

# vim: set ts=2 nolist :

出力

Numbers
=======
1
2
3
4
5
6

Letters
=======
A
B
C
D
E
F

答え3

あなたが提供した入力のnumberletters.sh:

#!/bin/bash

echo Numbers

for f in "$@"
do
   grep -E '^[0-9]+$' "$f" 
done

echo
echo Letters

for f in "$@"
do
    grep -E '^[A-Z]+$' "$f"
done

echo

numbersletters.sh file1 file2返品

Numbers
1
2
3
4
5
6

Letters
A
B
C
D
E
F

| sort -ufor for ループを追加すると、ソートされ、一意になります。

答え4

以下は、任意のヘッダー名で動作する単純なPerlソリューションです。

#!/usr/bin/env perl 
my ($last,$head); 
my %k;  ## this will hold our data
my $separator="=====";
my @lines=<>; ## Read all lines
for(my $i=0; $i<=$#lines; $i++){ ## for each line...
    next if $lines[$i]=~/$separator/; ##skip the separators
    next if $lines[$i]=~/^\s*$/;  ##skip empty lines
    if ($lines[$i+1]=~/====/) { ## if the NEXT line is a separator, 
    $head=$lines[$i];       ## the this line is a heading
    next;
    }
    else { ## save the contents of this group into the %k hash.
    push @{$k{$head}},$lines[$i];
    }
}

## Now print everything
foreach (keys(%k)) {
    print "$_========\n", @{$k{$_}};
}

関連情報