行・列の整理!Perlでデータを並び替えて整理する方法は?

このQ&Aのポイント
  • Perlを使用してデータを並び替えて整理する方法について知りたいです。
  • 元のデータを基に、目標のデータ形式に整理する方法を教えてください。
  • 正規表現を使って部分一致の行を処理する方法について教えてください。
回答を見る
  • ベストアンサー

行・列の整理! perl

perlでデータを並び替えて整理したいです。 【元データ】 A a b A c d A e f A g h B i j B k l B m n C o p C q r C s t C u v ・ ・ ・ 上記のデータを下記のように並び替えしたいのですが上手くできずに困っています。 どのような記述をすれば良いのでしょうか。間の空白はタブ区切りです。 【目標】 A a b c d e f g h B i j k l m n C o p q r s t u v D ・ 現在、元データから A B C D ・ ・ というデータを作り、元データと比較していますが上手くいきません。 for($i=0; $i<@key; $i++){ print OUT "$key[$i]"; for($j=0; $j<@data; $j++){ if($key[$i] =~ /$data[$j]/){    #部分一致 print OUT "$'"; } } print OUT "\n"; } 部分一致の行を正規表現を用いて上手く処理したいのですがやり方がわからず躓いています。 宜しくお願いします。

  • Perl
  • 回答数4
  • ありがとう数3

質問者が選んだベストアンサー

  • ベストアンサー
  • sample_
  • ベストアンサー率76% (20/26)
回答No.2

いまいち正確な仕様がわからないので・・・ 一番最初の文字をキーに並び替えを行うということで書いてみたのですが 大きな流れは、こんな感じ。 ファイルに書いてあるデータを読み込む。 1行ずつ受け取りタブでsplitする。 最初の文字をキーに配列に残りデータをpushする 出力。 おしまい。 #!/usr/bin/perl use strict; use warnings; #データの記載されたファイルを開く open my $fh, "<", "hoge.txt" or die $!; my (%hash, @data); while (my $line = <$fh>) { chomp($line); #行末の改行コードを削除する #1.tabで分割 @data = split(/\t/, $line); #2.ハッシュに、最初の文字をキーに。値を配列のリファレンスとみなし # 2番目の要素から最後の要素を配列のスライスとしてpushする push @{$hash{$data[0]}}, @data[1, -1]; } close $fh or die $!; #3.出力 for my $key (sort keys %hash){ #最初の文字(大文字のアルファベット)と残りを配列として扱い tabでjoinして出力 print join("\t", ($key, @{$hash{$key}})), "\n"; }

nanashim
質問者

お礼

目標とするファイルの作成ができました。 丁寧な説明までつけて頂き有難うございました。

その他の回答 (3)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

#2 を勝手に改造する試み: まず @data は while の中でしか使っていないので my の位置を移動する. ついでに分割するときに my ($key, @data) = split /\t/, $line; とすればそのあとが push @{$hash{$key}}, @data; と短くなる.

nanashim
質問者

お礼

効率良くするための試みですね。 勉強になります。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

@keyと@dataがそれだとすると > ・ $key[$i]が検索対象。 $data[$j] を探す と書いたように 「"A"の中に"A a b"にマッチする箇所があるか探す」 ことになります。見つかるわけがありません。

nanashim
質問者

お礼

回答有り難うございます。 基本的な理解が不十分でした。 正規表現及びメタ文字についてもう少し調べてみます。

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

「うまくいかない」とはどのような状態でしょう? その分析から始めるのがプログラミングのコツです。 if($key[$i] =~ /$data[$j]/){ これだと、 ・行の途中に $data[$j] がある場合でもマッチする。 ・ $key[$i]が検索対象。 $data[$j] を探す ・$data[$j]内に正規表現のメタ文字等が入っていると、文字検索ではなく正規表現検索になる という問題があります。 うまくいかないのは、これらの複合では?

nanashim
質問者

補足

回答ありがとうございます。 言葉足らずで申し訳ありません。 @key=A     B     C     ・     ・ @data=元データ と設定し、 OUTに出力する。 1.@keyのAをOUTに出力 2.for文を用いて@keyのAと、@dataのAを比較。 @keyのAと@dataのAが一致した時、@dataのAの行をOUTに抜き出す(Aの右側の部分のみ)。この繰り返しで@dataのAの行の右側部分を OUTに全て出力する。 3.改行する 4.1と同様に@keyのBをOUTに出力 以下同様の操作 という操作を行いたいと考えています。 $key[$i]が $data[$j]の頭の部分(例:A)と一致する場合に$data[$j]の後ろの部分(例:a b)を抜き出したいのですが、この場合にメタ文字をどのようにif文に組み込めば良いかというところがわかりません。 ・行の途中に $data[$j] がある場合でもマッチする。 →@keyのA,B,C..は@dataの頭の部分にしかないので  行の途中で一致するということは無いと思います。 ・$data[$j]内に正規表現のメタ文字等が入っていると、文字検索ではなく正規表現検索になる →a b等の間にタブが入っているので正規表現検索になっているということでしょうか? kmeeさんのおっしゃる通りこれらの複合ができてないのだと思います。

関連するQ&A

  • 2行のセルの入れ替え。

     初めまして、よろしくお願いします。  セルに A B C D E F G H I J K L 1 a b c d e f 2 g h i j k l 3 m n o p q r 4 s t u v w x 5 " ・ " ・ " ・ " 100 "  という表があります。これを A B C D E F G H I J K L 1 a b c d e f g h i j k l 2 m n o p q r s t u v w x 3 " 4 " 5 " ・ " ・ " ・ " 100 "  という風に、偶数行のデーターを奇数行の後ろにつけるようにしたいと思います。無理ならば奇数行だけのデーター、偶数行だけのデーターとなるように、何かよい方法を教えて頂きたく、よろしくお願いします。

  • C言語で文字列ではなく、文字の

    C言語で整数型の時は例えば int d[3][5]; などとおいて二次元配列を作り、文字列のときは char a[3][4]="abc,bcd,cde";(←ちょっとこの宣言も合っている自信はないが) という様に置きますよね。こういうのを文字でも利用して、 1 2 3 4 5....... A s t u v w x y.... B i u i k i k u.... C j j j j o o o.... :.................. :................. :................ という様な表を文字の2次元配列を使って printf("%c",c[i][I]); のように表したいのですが、int d[i][I]のように 文字を二次元配列を作ることは出来るんでしょうか? どなたか知っている方がいたら教えてください。

  • Perlで重複行を削除したい

    あ b c d e e g あ b c d e e g い b c d e e g い c c d e e g 上記のようなCSVデータ(タブ区切り)が100行くらいあるのですが、1列目にある、あ、あ、い、いは無視して、2列目以降のデータのみで重複を比較して同じ行は削除したいのですがどのようにすればよいでしょうか? 下記コードを応用すれば分かりそうなのですが、自分で作ることができませんでした。 どなたか、教えていただけ無いでしょうか? 宜しくお願い致します。 open(OUT, "$file"); @array = <OUT>; close(OUT); my %count; @array = grep(!$count{$_}++, @array); print @array;

    • ベストアンサー
    • CGI
  • MS-excel 10列毎に改行したい

    MS-excel2003で、A1~W1までデータが横並びに入力されています。 これを10列毎に改行したいのですが、マクロでどのようにやればよいでしょうか? 図解すると、、 A1 B1 C1 D1 F1 G1 H1・・・・ のデータを A1 B1 C1 D1 F1 G1 H1 I1 J1 K1 L1 M1 N1 O1 P1 Q1 R1 S1 T1 U1 V1 W1・・・・・・ と したいのです。 これをマクロで行いたいのですが、ご教授願えませんか。

  • 3行3列の行列(近似値)を求めたい

    A,B,C,I,J,Kの6つの既知の変数に対して 以下の行列式を成立させるa1~a3, b1~b3, c1~c3が 存在するとします。 (A B C) | ※求めたい行列 | = (I J K) ※求めたい行列 | a1 a2 a3 | | b1 b2 b3 | | c1 c2 c3 | A,B,C,I,J,Kが1通りであれば3×3行列は決定できると思いますが、 A,B,C,I,J,Kの組が複数ある場合、完全に条件を満たす3×3行列が あるとは限らず、実際のところ近似値になると思います。 A,B,C,I,J,Kは、幾通りあるにせよ既知の定数です。 例としてデータの組は添付ファイルのように複数あるとします。 近似的に3×3行列を求めるには、どのような計算を行えば 良いのでしょうか? そのような計算をExcelで行う方法、又はそれが可能なフリーソフトなど ありましたら教えて頂けませんでしょうか?

  • C言語で2次元配列の引数定義やコピーの仕方など

    2次元配列の引数の定義や渡し方や ある変換する関数で、すべて' '(スペース)にしたり[memmoveなど1命令で]や、 それぞれ一つ違う値 A->B, O->Pに置き変える関数しようとしているのですが、 C言語のデータ操作に非常に疎く、どのようにすれば良いかわかりません。 どのようにすれば良いのでしょうか? 環境はWindowsで VisualC++6.0です。 GCCもソースを変えずに同じように出来るのでしょうか? #include <stdio.h> char lesson[7][6] = { {'A', 'B', 'C', 'D', 'E', 'F'}, // MON {'G', 'H', 'I', 'J', 'K', 'L'}, // TUE {'M', 'N', 'O', 'P', 'Q', 'R'}, // WED {'S', 'T', 'U', 'V', 'W', 'X'}, // THU {'Y', 'Z', 'a', 'b', 'c', 'd'}, // FRI {'e', 'f', 'g', 'h', 'i', 'j'}, // SAT {'k', 'l', 'm', 'n', 'o', 'p'}, // SUN }; // --- 多次元配列の引数の渡し方がわからないのでvoid --- void print_data(void) { for(int i=0; i < 7; i++){ for(int j=0; j < 6; j++){ printf("%c ", lesson[i][j]); } printf("\n"); } } // --- 問題の変換関数(引数定義と内容 --- int convert(????) { ???? } // --- メイン --- int main(boid){ print_data(); conver(???); // <--- どのように引数に渡すのか? print_data(); return 0; }

  • perl 文字列検索後に指定フィールドの値を変数へ

    菊池と申します。 perlスクリプトで下記のような文字列を検索し、検索されたら指定したフィールドの値を変数に入れたいのですが、grepやawkを使うと、ファイル中のすべてが検索対象になってしまい困っております。 文字列検索の表現方法をご教授頂けると大変助かります。 下記へperlスクリプトの一部を記載させて頂きました、データはcsv形式です。 変数に入れる事が出来なかったので、抽出した値をファイルへ出力させています。 検索文字列=2013/11/19,09:00:00,13:00:00 データの中味 <94>N/<8c><8e>/<93>ú,<89>ð<90>Í<8a>J<8e>n<8e><9e><8d><8f>,<89>ð<90>Í<8f>I<97>¹<8e><9e><8d><8f>,<8c>ö<8b>¤<8d>À<95>WX(m),<8c>ö<8b>¤<8d>À<95>WY(m),<95>W<8d><82>H(m),<88>Ú<93>®<95>½<8b>Ï<92>lX(m),<88>Ú<93>®<95>½<8b>Ï<92>lY(m),<88>Ú<93>®<95>½<8b>Ï<92>lH(m),<8f><89><8a>ú<92>l<82>©<82>ç<82>Ì<95>Ï<93>®<97>ÊX(m),<8f><89><8a>ú<92>l<82>©<82>ç<82>Ì<95>Ï<93>®<97>ÊY(m),<8f><89><8a>ú<92>l<82>©<82>ç<82>Ì<95>Ï<93>®<97>ÊH(m),2D<8b><97><97>£(m),3D<8b><97><97>£(m),<88>Ú<93>®<95>½<8b>Ï2D<8b><97><97>£(m),<88>Ú<93>®<95>½<8b>Ï3D<8b><97><97>£(m),<91>ª<88>Ê<83>t<83><89><83>O,<91>ª<88>Ê<90>¸<93>x,<88>Ù<8f>í<92>l<83>t<83><89><83>O<81>i<8f><89><8a>ú<92>l<81>j,<88>Ù<8f>í<92>l<81>i<8c>x<89>ú<83><89><83><93><83>N<81>j,<94>ò<82>Ñ<92>l<83>t<83><89><83>O, 2013/11/18,01:00:00,05:00:00,-68213.2327,17746.2653,2093.7982,-9999.0000,-9999.0000,-9999.0000,5.0099,-0.5989,-4.8100,16215.1100,16255.8006,-9999.0000,-9999.0000,4,0.0019,0,0,0, 2013/11/18,05:00:00,09:00:00,-68213.2273,17746.2666,2093.7872,-9999.0000,-9999.0000,-9999.0000,5.0153,-0.5976,-4.8210,16215.1061,16255.7959,-9999.0000,-9999.0000,4,0.0014,0,0,0, 2013/11/18,09:00:00,13:00:00,-68213.2256,17746.2692,2093.7792,-9999.0000,-9999.0000,-9999.0000,5.0170,-0.5950,-4.8290,16215.1030,16255.7923,-9999.0000,-9999.0000,4,0.0016,0,0,0, 2013/11/18,13:00:00,17:00:00,-68213.2236,17746.2737,2093.7682,-9999.0000,-9999.0000,-9999.0000,5.0190,-0.5905,-4.8400,16215.0981,16255.7866,-9999.0000,-9999.0000,4,0.0014,0,0,0, 2013/11/18,17:00:00,21:00:00,-68213.2306,17746.2741,2093.7672,-9999.0000,-9999.0000,-9999.0000,5.0120,-0.5901,-4.8410,16215.1015,16255.7899,-9999.0000,-9999.0000,4,0.0016,0,0,0, 2013/11/18,21:00:00,01:00:00,-68213.2308,17746.2739,2093.7882,-9999.0000,-9999.0000,-9999.0000,5.0118,-0.5903,-4.8200,16215.1017,16255.7916,-9999.0000,-9999.0000,4,0.0016,0,0,0, 2013/11/19,01:00:00,05:00:00,-68213.2221,17746.2743,2093.8062,-9999.0000,-9999.0000,-9999.0000,5.0205,-0.5899,-4.8020,16215.0968,16255.7880,-9999.0000,-9999.0000,4,0.0017,0,0,0, 2013/11/19,05:00:00,09:00:00,-68213.2140,17746.2808,2093.7982,-9999.0000,-9999.0000,-9999.0000,5.0286,-0.5834,-4.8100,16215.0870,16255.7777,-9999.0000,-9999.0000,4,0.0013,0,0,0, 2013/11/19,09:00:00,13:00:00,-68218.2472,17746.8587,2098.6543,-9999.0000,-9999.0000,-9999.0000,-0.0046,-0.0055,0.0461,16217.2238,16258.2532,-9999.0000,-9999.0000,4,0.0017,0,0,1, 2013/11/19,13:00:00,17:00:00,-68218.2538,17746.8600,2098.6633,-9999.0000,-9999.0000,-9999.0000,-0.0112,-0.0042,0.0551,16217.2263,16258.2563,-9999.0000,-9999.0000,4,0.0014,0,0,1, 2013/11/19,17:00:00,21:00:00,-68218.2603,17746.8538,2098.6473,-9999.0000,-9999.0000,-9999.0000,-0.0177,-0.0104,0.0391,16217.2349,16258.2638,-9999.0000,-9999.0000,4,0.0016,0,0,1,   <<スクリプトの一部>> #`grep "'2013/11/19,09:00:00,13:00:00'" $SS | awk -F"," '{print \$13}' $SS > $SS-2D`; #`grep "'2013/11/19,09:00:00,13:00:00'" $SS | awk -F"," '{print \$14}' $SS > $SS-3D`; `awk -F"," '\$1 ~ \/2013\/11\/19\/ && \$2 == \/09\:00\:00\/ {print \$13}' $SS > $SS-2D`; `awk -F"," '\$1 ~ \/2013\/11\/19\/ && \$2 == \/09\:00\:00\/ {print \$14}' $SS > $SS-3D`; 以上 よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • perl初心者です。宜しくお願い致します。

    ファイルの容量が大きく。perlを使用してデータの集計をしています。 "A"がきたらflag1をたてなさい。 "B"がきたらflag2をたてなさい。 "C"がきたらflag3をたてなさい。 これでAとBとCを抜き取ること&AからCまでの時間を取得したのですが、 Bの数のmaxの値だけを抜き取りたいのですが、Bがきたときの数をすべて 出力してしまいます。下記の文だと、Bが4回きたら、1,2,3,4と出力してしまいます。 それで4だけを出力したいのですがどのように書き換えたらようか教えて頂けますでしょうか。 '----------------------------------------------------------------------------- open (IN,"< $ARGV[0].txt") or die; open (OUT,"> $ARGV[0]_out.txt") or die; $flag =0; my $a, $b, $c; $count = 0; ####################################################### while($line =<IN>){ ($time,$data) = split(/\s+/,$line); if($data eq "A") { $flag=1; $a = $time; #print OUT $line; #print OUT "\n"; } elsif($data eq "B"){ $flag=2; $count++; $count == $data; print OUT ("$count\n") } #print OUT ("$count\n"); elsif($data eq "C"){ $flag=0; $count=0; $b = $time; $c = $b - $a; print OUT ("time $c\n") } } -------------------------------------------------------------------------------

  • 2×2行列の掛け算をするプログラム

    タイトルのプログラムなんですが、授業で例題としてソース渡されたんですが、学校のUNIXのやつだと動くんですけど、自分の使ってるVC++だと動かないんですよ。 その理由と、VC++で動くようにするにはどうしたらいいかおしえてください。 ソースは、 #include<stdio.h> void get_data(); void write_data(); void product(); main() { double a[2][2],b[2][2],c[2][2]; get_data(a); get_data(b); write_data(a); write_data(b); product(a,b,c); write_data(c); } void get_data(double p[][2]) { int i,j; printf("Input elements\n"); for(i=0;i<2;i++) for(j=0;j<2;j++){ printf("(%d,%d)-th element=",i,j); scanf("%lf",&p[i][j]); } } void write_data(double p[][2]) { int i,j; printf("\n"); for(i=0;i<2;i++){ for(j=0;j<2;j++) printf("(%d,%d)-th element=%lf\t",i,j,p[i][j]); printf("\n"); } printf("\n"); } void product(double u[][2],double v[][2],double w[][2]) { int i,j,k; for(i=0;i<2;i++) for(j=0;j<2;j++){ w[i][j]=0.0; for(k=0;k<2;k++) w[i][j]+=u[i][k]*v[k][j]; } } です。 よろしくおねがいします。

  • 条件部分の行だけ取り出すPerlが動きません(DOS窓)

    ------------------------------------ c:\work\a.bat c: cd \work convert.pl sample.html convert.pl sample1.html convert.pl sample2.html … ------------------------------------- c:\work\convert.pl $infile=$ARGV[0]; $outfile=$ARGV[0]; # 変換後ファイルは、拡張子をtxtにして区別 $outfile=~ s/\.html/\.txt/; # ファイルを開く open( IN, $infile ); @xx = <IN>; close(IN); # 抽出行の先頭行番号を取得 $i=0; for (@xx) { if ($xx[$i]= ~ /Array/){ $start = $i; last; } $i++; } # 抽出行の最後行番号を取得 for ($j = $start; $j <= 100; $j++) { if ($xx[$j]= ~ /\)\;/){ $end = $i; last; } $j++; } # 書き込み用にファイルを開く open( OUT, "> $outfile" ); for ($k = $start; $k <= $end; $k++) { print(OUT $xx[$k]); } # ファイルを閉じる close( OUT ); ------------------------------------- c:\work\sample.html <html> <head> <script type="text/JavaScript"> <!-- sample(); var a = new Array("ああああ", "いいいい", "うううう"); var b = new Array("ええええ", "おおおお", "おおおお"); function init(){ } --></script> </head> <body onload="init();"> </body> </html> ------------------------------ というようにファイルを作り、a.batを実行すると、 htmlファイルのvar aに該当する行(sample.htmlの場合、6~8行目)だけ 取り出して別ファイルに吐き出すようなプログラムを作ってみたのですが、 うまく動きません。 なお、単純にforeach文で@xxをoutfileに出力するのはできました。 部分だけ取り出そうとすると失敗しました。 どこを直せばいいのでしょうか?

    • ベストアンサー
    • Perl

専門家に質問してみよう