質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.93%

テキストファイルから複数指定した条件での抽出と加工

解決済

回答 5

投稿

  • 評価
  • クリップ 1
  • VIEW 264

natsu25

score 43

#start
#
#
#
#
#
#


ID: 11223344556677
NAME: XXXX-XXX
MAIL: xxxxx@xxxx.ne.jp


ID: 112233445566
NAME: XXXXXX-XX
MAIL: xxxxx@xxxx.ne.jp


ID: 1122
NAME: XXX-XXX
MAIL: xxxxx@xxxx.ne.jp


ID: 1234567
NAME: XX-XXXXX
MAIL: xxxxx@xxxx.ne.jp


ID: 1122334455
NAME: XXXXX-XXX
MAIL: xxxxx@xxxx.ne.jp


# search result
search: 5
result: 5

#
#end

上記のような形式のファイルから以下のような条件で抽出するにはどのような記述をすれば良いでしょうか?
先頭から7列目以降という条件は awk -F '=' 'NR > 8 {print $0}'" で出来そうかと思いますがその他の方法が分かっておりません。

① 先頭から7列目以降~末尾から8列目以前

② ①を除いたものから2列おきに3列ずつ取得

③ 取得した3列から改行を削除し1列にする
例:ID: 1122334455NAME: XXXXX-XXXMAIL: xxxxx@xxxx.ne.jp

④ID/NAME/MAILを抽出し別々のファイルに出力
※ID/NAME/MAILの文字数は定まっていないです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hidezzz

    2020/07/09 20:13

    ④の「別々のファイル」とは1件のIDとNAMEとMAILの単位で1ファイルずつ出力という意味?それとも全ID、全NAME、全IDの3種類でそれぞれファイルを作るという意味ですか?

    キャンセル

  • natsu25

    2020/07/09 21:09

    >IDとNAMEとMAILの単位で1ファイルずつ出力という意味
    こちらの意味です。分かりづらく申し訳ありません。

    キャンセル

  • takasima20

    2020/07/09 21:17

    その場合のネーミングルールはどうなりますか?

    キャンセル

回答 5

checkベストアンサー

0

「列」と「行」を間違えてますね。

sedawkのようにフィルター的に処理するコマンドでは、「最後の8行を除外」は困難です。
案1:まず全体の行数を調べてから、処理を始める
案2:複数行をメモリ上に保存しながら処理する
のどちらか。

awk -v LINE=`wc -l < data.txt` 'NR>7 && NR<LINE-7 {~~~}' data.txt
awk '{data[NR]=$0}END{for(i=8;i<NR-7;i++){~data[i]の処理~}}'  data.txt

ファイル全体がメモリに乗る量なら、案2が楽そうです。

awk '{data[NR]=$0}END{
  for(i=8;i<NR-7;i+=5){ print data[i+2] data[i+3] data[i+4]}
}' data.txt

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

とりあえず③まで(,などのセパレーターは付けないでいいのかな?)

awk '/^(ID|NAME):/ {printf $0 } /^MAIL:/ {print $0}' 

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

別ファイルってことなので grep 使ってみました。

awk '/ID: /{id=$0} /NAME: /{name=$0} /MAIL: / {print id name $2}' hoge.txt
grep 'ID' hoge.txt | sed 's/ID: //' >id.txt
grep 'NAME' hoge.txt | sed 's/NAME: //' >name.txt
grep 'MAIL' hoge.txt | sed 's/MAIL: //' >mail.txt


--- 追記 ---
仕様が違ったようなので

awk '/ID: /{id=$0} /NAME: /{name=$0} /MAIL: / {print id name $2}' hoge.txt
grep -e 'ID' -e 'NAME' -e 'MAIL' hoge.txt | split -l 3

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

まあすべての条件を満たすとなるとperlが一番ラクじゃないでしょうかね
ちゃんとテストしてませんが、こんな感じで。

#!/usr/bin/env perl
use strict;
use warnings;

my @data;
while(<>){
  chomp;
  push(@data, $_);
}

my $id=0;
my $fho;
foreach my $d (@data[7..$#data-8]){
  if($d=~/^ID/){
    $id++;
    open($fho, '>', "out$id.txt");
    print {$fho} "$d\n";
  }elsif($d=~/^NAME/ or $d=~/^MAIL/){
    print {$fho} "$d\n";
  }
}
close $fho;

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

ファイル形式が確定しているのであれば
複数行レコードととらえて、改行をフィールドセパレータにすれば
すっきりしていいんじゃないかな。
各ファイルにレコードインデックスを添えると、のちのち便利かも。

#foo.awk

BEGIN {
    RS = "\n\n\n";
    FS = "\n";
}

/^ID:/ {
    sub(/ID: /, "", $1);
    sub(/NAME: /, "", $2);
    sub(/MAIL: /, "", $3);
    printf("%04d %s\n", ++c, $1) >> "id.txt";
    printf("%04d %s\n", c, $2) >> "name.txt";
    printf("%04d %s\n", c, $3) >> "mail.txt";
}
awk -f foo.awk data.txt

実行結果

id.txt
0001 11223344556677
0002 112233445566
0003 1122
0004 1234567
0005 1122334455

name.txt
0001 XXXX-XXX
0002 XXXXXX-XX
0003 XXX-XXX
0004 XX-XXXXX
0005 XXXXX-XXX

mail.txt
0001 xxxxx@xxxx.ne.jp
0002 xxxxx@xxxx.ne.jp
0003 xxxxx@xxxx.ne.jp
0004 xxxxx@xxxx.ne.jp
0005 xxxxx@xxxx.ne.jp

補足解釈およびコメントをいただいて

#foo2.awk

BEGIN {
    RS = "\n\n\n";
    FS = "\n";
}

/^ID:/ {
    sub(/ID: /, "", $1);
    sub(/NAME: /, "", $2);
    sub(/MAIL: /, "", $3);
    recfile = "rec" sprintf("%04d", ++c) ".txt"
    printf("%s\n", $1 "/" $2 "/" $3) > recfile;
}
awk -f foo2.awk data.txt

実行結果
rec0001.txt
11223344556677/XXXX-XXX/xxxxx@xxxx.ne.jp
rec0002.txt
112233445566/XXXXXX-XX/xxxxx@xxxx.ne.jp
rec0003.txt
1122/XXX-XXX/xxxxx@xxxx.ne.jp
rec0004.txt
1234567/XX-XXXXX/xxxxx@xxxx.ne.jp
rec0005.txt
1122334455/XXXXX-XXX/xxxxx@xxxx.ne.jp

こんなんでいいのでしょうか。読解力なくてすみません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/10 08:57

    質問者の説明が曖昧ですが、その後の補足によると、一件ずつ「ID/NAME/MAIL」をファイルにまとめて、データの件数分の個数のファイルを出力する、ということを言いたかったらしい。

    キャンセル

  • 2020/07/10 09:12 編集

    コメントありがとうございます。
    追記を読んで混乱。お題に「抽出」とあるように、どう見ても上記3ファイルの作成を意図しているように思うのだけれど、「1件のIDとNAMEとMAILの単位で1ファイルずつ出力」っていう変な質問で意味が分からなくなった。1レコードにつき1ファイル必要と言っているのかな?「抽出」どこいったんだろう。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る