不規則なデータファイルをコマンドラインでcsvファイルに整形したいです。どなたか教えていただけないでしょうか?
- 評価
- クリップ 0
- VIEW 1,843
手作業で整形していたら時間がかかるようなファイルを
コマンド一行で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ページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
+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の処理では、名前ー住所その他の対応関係をつけることが全くできないように思います。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
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)になります。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.35%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正、ベストアンサー選択の依頼
otn
2017/08/31 14:52 編集
レコードの区切りはどういう基準で行いますか?
dlrowolleh
2017/08/31 15:33 編集
大変失礼いたしました。result.csvを書き間違えていました。
「ほげほげ」「電話い」はsample1.txtにありませんでした。
質問を修正します。