重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

電子書籍の厳選無料作品が豊富!

Perlでのテキスト処理について質問です。

テキストファイルの中身が下記のようになっています。

【テキスト編集前】
---------------------------------------
test ,abc ,AB ,VI ,SS ,ma ---1行目
test ,abc ,AC ,PI ,VS ,ma ---2行目
test ,abc ,BA ,SS ,VS ,ma ---3行目
test ,abc ,BA ,VI ,VS ,ma ---4行目
test ,cde ,AA ,VI ,SS ,mb ---5行目
test ,cde ,CC ,PE ,VS ,mb ---6行目
test ,cde ,BC ,PI ,SS ,mb ---7行目
test ,cde ,AC ,PI ,SS ,mc ---8行目
---------------------------------------

2列目(abc/cde)と6列目(ma/mb/mc)が同じ行に対しては
1行にまとめて出力したいと思っています。

この時、1列目、4列目、5列目はマージした形にし
(同一文字は一度だけ出力、同一でない文字は/区切りで出力)、
2列目、6列目は同一文字をそのまま出力し、
3列目に関しては、該当する行の先頭行の文字列を
出力したいと思っています。

下記が当方の希望しているPerl実行後の出力結果です。
【テキスト編集後】
---------------------------------------
test ,abc ,AB ,VI/PI/SS ,SS/VS ,ma
test ,cde ,AA ,VI/PE/PI ,SS/VS ,mb
test ,cde ,AC ,PI ,SS ,mc
---------------------------------------

このような編集をPerlで実行したいと思っているのですが、
どのような記述をすれば実行できるのか教えて頂けないでしょうか。

当方、Perlを始めたばかりで基本的なことを
伺っているのかもしれませんが
すみませんが、ご了承ください。

宜しくお願いいたします。

A 回答 (5件)

ところで普通はカンマの後ろに空白を置いて、前には置かないんじゃないですかね。



use strict;
use warnings;
use autodie;
use v5.10;

sub dump_data {
my $data_ref = shift;
given (ref($data_ref)) {
when ("ARRAY") {
say join(',', @{$data_ref});
}
when ("HASH") {
foreach my $e (sort keys %{$data_ref}) {
dump_data($data_ref->{$e});
}
}
default {
warn "invalid data";
}
}
}

sub get_contents {
my $fh;
if (@ARGV) {
open $fh, '<', shift @ARGV;
}
else {
$fh = *DATA;
}

chomp(my @lines = <$fh>);
close $fh;
@lines;
}

#main
my %data;
foreach my $line (get_contents) {
my @fields = split /\s*,\s*/, $line;
if (exists $data{$fields[0]}{$fields[1]}{$fields[5]}) {
my $ary_ref = $data{$fields[0]}{$fields[1]}{$fields[5]};
foreach my $i (0, 3, 4) {
$ary_ref->[$i] .= "/$fields[$i]" if index($ary_ref->[$i], $fields[$i]) < 0;
}
}
else {
$data{$fields[0]}{$fields[1]}{$fields[5]} = \@fields;
}
}

dump_data(\%data);

__END__
test ,abc ,AB ,VI ,SS ,ma
test ,abc ,AC ,PI ,VS ,ma
test ,abc ,BA ,SS ,VS ,ma
test ,abc ,BA ,VI ,VS ,ma
test ,cde ,AA ,VI ,SS ,mb
test ,cde ,CC ,PE ,VS ,mb
test ,cde ,BC ,PI ,SS ,mb
test ,cde ,AC ,PI ,SS ,mc
    • good
    • 0

個人的にはハッシュの方がいいかなと思ったり>#3.

    • good
    • 0

新規行を配列等に保存しておいて、2、6列目の同じ行が現れたら保存しておいた行を修正するというようなやり方があります。



use strict;
my @result;

NEXT: while (<DATA>) {
my @line = split /[,\s]+/;
foreach my $ref (@result) {
if ($line[1] eq $$ref[1] and $line[5] eq $$ref[5]) {
$$ref[0] .= "/$line[0]" if $$ref[0] !~ /\b$line[0]\b/;
$$ref[3] .= "/$line[3]" if $$ref[3] !~ /\b$line[3]\b/;
$$ref[4] .= "/$line[4]" if $$ref[4] !~ /\b$line[4]\b/;
next NEXT;
}
}
push @result, \@line;
}

print join(',', @$_), "\n" foreach @result;

__DATA__
test ,abc ,AB ,VI ,SS ,ma
test ,abc ,AC ,PI ,VS ,ma
test ,abc ,BA ,SS ,VS ,ma
test ,abc ,BA ,VI ,VS ,ma
test ,cde ,AA ,VI ,SS ,mb
test ,cde ,CC ,PE ,VS ,mb
test ,cde ,BC ,PI ,SS ,mb
test ,cde ,AC ,PI ,SS ,mc
    • good
    • 0

まあ,丸投げですなあ>No.1



こういうのって・・・他の人はどう作るかわからないけど
最低限

プログラムではなく手動でやるときにどうするのか?

ってことが自分で整理できないと何もできないんだよね.
質問者は
したい作業を手動でエディタでできるのかい?

エディタでできるなら次にその工程を整理して
一個一個の作業を整理して
出来るかぎり小さな作業にばらして
その小さな作業を一個一個プログラムにするとか
そういうことができないのかな?

そうすれば,自然とプログラム全体ができるし
どこをコード化できないか切り分けもできるでしょう
    • good
    • 0

要するにスクリプト作成丸投げ?

    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!