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

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

ただいまの
回答率

90.53%

  • 正規表現

    912questions

    正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

  • CSV

    836questions

    CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

  • コマンドライン

    111questions

    コマンドライン(別名:Command Line Interface)は、ユーザに命令の入力を促す(プロンプト)文字列の表示を行い、すべての操作をキーボードを用いて文字列を打ち込む事でプログラムを走らせるユーザインターフェースです。

  • AWK

    84questions

    AWKは、UNIX 上で開発されたプログラミング言語で、CSVファイルなどのテキストファイルの処理を目的にデザインされています。

  • sed

    69questions

    sedとは、POSIX環境のために作られたコマンドラインエディタです。sedは編集スクリプトの指示のもとに複数のファイルを編集し、標準出力にその結果を出力します。

不規則なデータファイルをコマンドラインでcsvファイルに整形したいです。どなたか教えていただけないでしょうか?

受付中

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 953

dlrowolleh

score 112

手作業で整形していたら時間がかかるようなファイルを
コマンド一行でcsvファイルに変換したいです。
どなたかエレガントなやり方を教えていただけないでしょうか?

sample1.txt

 名前 あ
住所 住所あ
 電話 電話あ

名前 い
   電話 ※※
年齢 年齢い

年齢 年齢う

名前 う
住所:住所う
電話 電話う

名前 ほげほげ
住所=住所え
            電話 電話え
名前=名前お
電話 電話お

年齢 年齢お
住所 住所お


のような

・Tab、半角スペース、全角スペースで始まる
・ヘッダにしたい情報とデータとして扱いたい情報との間に
半角スペース、全角スペース、Tab,=,=,:がある
・不規則にデータが保存されている

ファイルsample1.txtがあります。
このファイルをresult.csvのようなcsv形式のファイルに整形したいのですが,
どなたかエレガントなやり方を教えていただけませんか?

result.csv

名前,年齢,住所,電話番号
あ,,住所あ,電話あ
い,年齢い,,電話い
う,年齢う,住所う,電話う
名前え,,住所え,電話え
名前お,年齢お,住所お,電話お


私は以下のようにコマンドを実行しました。

$ grep 名前 sample1.txt | cut -f2 -d ' ' | sed -e "s/\$/,/" 2>&1 | tee 名前.txt 
$ grep 年齢 sample1.txt | cut -f2 -d ' ' | sed -e "s/\$/,/" 2>&1 | tee 年齢.txt 
$ grep 住所 sample1.txt | cut -f2 -d ' ' | sed -e "s/\$/,/" 2>&1 | tee 住所.txt 
$ grep 電話 sample1.txt | cut -f2 -d ' ' | sed -e "s/\$/,/" 2>&1 | tee 電話.txt 
$ paste 名前.txt 年齢.txt 住所.txt 電話.txt >kekka.csv

その結果、以下のようなcsvファイルkekka.csvファイルができました。

名前,    年齢い,    住所あ,    電話あ,
い,    年齢 年齢う,    住所:住所う,    ,
う,    年齢お,    住所=住所え,    電話う,
ほげほげ,        住所お,    電話え,
名前=名前お,            電話お,

問題点として

<sample1.txt・処理のやり方が原因?>
・Tab、半角スペース、全角スペースで始まる
・ヘッダにしたい情報とデータとして扱いたい情報との間に
半角スペース、全角スペース、Tab,=,=,:がある
<処理のやり方が原因?>
・csvファイルのヘッダ情報がない
・pasteした時にTabで勝手にインデントされている
・カンマ,の数が合っていない

が考えられます。

sample1.txtからresult.csvを作成するにはどのようにすればいいでしょうか?
こういったファイルをcsv形式にする機会が多く、最終的に手作業に頼ることになり、
時間がかかり毎回気が滅入っております。

アドバイスいただけましたら幸いです。
よろしくお願いします。

修正

result.csv

名前,年齢,住所,電話
あ,,住所あ,電話あ
い,年齢い,,※※
う,年齢う,住所う,電話う
ほげほげ,,住所え,電話え
名前お,年齢お,住所お,電話お

です
大変失礼いたしました。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • otn

    2017/08/31 14:52 編集

    レコードの区切りはどういう基準で行いますか?

    キャンセル

  • dlrowolleh

    2017/08/31 15:33 編集

    大変失礼いたしました。result.csvを書き間違えていました。
    「ほげほげ」「電話い」はsample1.txtにありませんでした。
    質問を修正します。

    キャンセル

回答 4

+2

こういうのはどうでしょう。今、ちょっと忙しいので、書きっぱなしでろくに検証していませんが。

BEGIN {
    no_of_fields = split("名前,年齢,住所,電話", keys, ",");
    for (i = 1; i <= no_of_fields; i++) {
        key2index[keys[i]] = i;
    }
    line = "";
    for (i = 1; i <= no_of_fields; i++) {
        line = line "," keys[i];
    }
    print substr(line, 2);
}

{
    key = $1;
    idx = key2index[key];
    val = $2;
}

{
    if (fields[idx] != "") {
        flush();
    }
    fields[idx] = val;
    vals++;
}

END {
    if (vals > 0) {
        flush();
    }
}

function flush() {
    line = "";
    for (i = 1; i <= no_of_fields; i++) {
        line = line "," fields[i];
        fields[i] = "";
    }
    print substr(line, 2);
    vals = 0;
}

実行は次のように。

$ sed -e 's/^\s\+//g' -e 's/[\s:==]/ /g' sample1.txt | awk -f pretify.awk
名前,年齢,住所,電話
あ,,住所あ,電話あ
い,年齢い,,※※
う,年齢う,住所う,電話う
ほげほげ,,住所え,電話え
名前お,年齢お,住所お,電話お

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

根本的な問題として、レコードを区別する基準が不明瞭のようです。

名前 ほげほげ
住所=住所え
            電話 電話え
名前=名前お
電話 電話お

これは1件としますか?2件としますか?
上記のgrepの処理では、名前ー住所その他の対応関係をつけることが全くできないように思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/08/31 15:37

    ご回答いただきありがとうございます。
    >根本的な問題として、レコードを区別する基準が不明瞭のようです。
    おっしゃるとおりでした。
    大変失礼いたしました。result.csvを書き間違えていました。
    「ほげほげ」「電話い」はsample1.txtにありませんでした。
    質問を修正します。

    キャンセル

  • 2017/08/31 15:56

    依然として疑問を解消できません。
    あと、「年齢 年齢う」はどのレコードに入るのですか?

    言い換えると、「空行をレコードの区切りとする」・「名前が出てきたら新しいレコードの始まりとする」の2つの可能性が考えられるように思いますが、どちらですか? それともそれ以外の基準がありますか?

    キャンセル

0

ご提示の例とお答えと同じになる様にはしてみました。

echo 名前,年齢,住所,電話
sed -e"s/^[ \t]*//" -e"s/\t/ /g" -e"s/[==:]/ /" sample1.txt |
awk '{if($1 in v){printf"%s,%s,%s,%s\n",v["名前"],v["年齢"],v["住所"],v["電話"];delete v;}v[$1]=$2}END{printf"%s,%s,%s,%s\n",v["名前"],v["年齢"],v["住所"],v["電話"]}'

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

フローとしては以下のような感じでしょうか。

(1)先頭の不要スペースを削除する
(2)区切り文字を統一する
(3)空行から空行までを一まとまりとして処理
ハッシュを利用し、ヘッダ名称と値をそれぞれ格納
一まとまりが終わるまで上記を実施

ヘッダ順にカンマを挿入しながら出力

年齢 年齢う

名前 う
住所:住所う
電話 電話う


残念ながら上記がうまく処理できません。
これはヘッダが全て存在しているという過程が成り立てば処理ができますが、そうでない場合、どのように一まとまりと判断するか適切に判断できないためです。

名前 ほげほげ
住所=住所え
            電話 電話え
名前=名前お
電話 電話お

年齢 年齢お
住所 住所お


こちらもKojiDoiさんが指摘の通りです。
先の問題は、名前がない場合は次の塊も同じブロックと判断するとか、あるかもしれませんが、次の問題は次のブロックと判断したいところですが、先の問題との兼ね合いでうまく両者を同じように処理できないと思われます。

まとめると、ヘッダが全てあるわけではなく、その順番も決まっていないため、一つのブロックとして扱うべきデータの分離ができないことです。
何かしらそれができる方法、ルールが必要で、それを上記のステップのいずれかに入れる必要があります。基本的には(3)になります。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

  • 正規表現

    912questions

    正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

  • CSV

    836questions

    CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

  • コマンドライン

    111questions

    コマンドライン(別名:Command Line Interface)は、ユーザに命令の入力を促す(プロンプト)文字列の表示を行い、すべての操作をキーボードを用いて文字列を打ち込む事でプログラムを走らせるユーザインターフェースです。

  • AWK

    84questions

    AWKは、UNIX 上で開発されたプログラミング言語で、CSVファイルなどのテキストファイルの処理を目的にデザインされています。

  • sed

    69questions

    sedとは、POSIX環境のために作られたコマンドラインエディタです。sedは編集スクリプトの指示のもとに複数のファイルを編集し、標準出力にその結果を出力します。

  • トップ
  • AWKに関する質問
  • 不規則なデータファイルをコマンドラインでcsvファイルに整形したいです。どなたか教えていただけないでしょうか?