理系公務員のプログラミング日記

【シェルプログラミング】grepとsedと正規表現

タグ:
シェルプログラミング

クイズゲームのデータセット

JavaScriptのクイズゲームの作成のために、クイズゲームのデータセットが欲しかったので探していると、 AI王 〜クイズAI日本一決定戦〜なんてサイトを発見。 クイズデータを学習させたAI同士で競わせるコンペだそうで。最近kaggleやってないな〜

大量のクイズデータを配布していたので拝借してみました。
こんな感じのデータがテスト用の軽いデータセットでも700kBくらい。

{ "qid": "QA20CAPR-0004", "question": "『non・no』『週刊プレイボーイ』『週刊少年ジャンプ』といえば、発行している出版社はどこでしょう?", "answer_entity": "集英社", "answer_candidates": [ "文藝春秋", "白泉社", "講談社", "宝島社", "扶桑社", "光文社", "集英社クリエイティブ", "双葉社", "幻冬舎", "リイド社", "集英社", "秋田書店", "潮出版社", "徳間書店", "小学館", "実業之日本社", "日本文芸社", "学研ホールディングス", "マガジンハウス", "祥伝社" ], "original_question": "『non・no』『週刊プレイボーイ』『週刊少年ジャンプ』といえば、発行している出版社はどこでしょう?" }

1問ごとにJSONの形になっているけど、全体を[]で囲った上で各問題の間にコンマがないので、このままではjavascriptで読み込めない。
クイズデータセットのJSONファイルのエラー

Pythonならこの形のままで読み込めるのかな?(忘れた)

ついでにキーの数が多くて授業で使うには少し不便そう。

大量データをシェルプログラミングと正規表現で弄り倒す

プログラマの三大美徳とは「怠惰」「短期」「傲慢」です。
気合を入れれば各データの間にコンマを追加していらないキーを消すことは出来るけど、それは三大美徳に反するので楽をしようと思います。

grepコマンドで文字列を検索する

shellで扱えるgrepコマンドでは指定ファイルの中から文字列を検索できます。
grep [オプション] 検索パターン 入力ファイル と入力します。
試しに同一ディレクトリにクイズのデータセットを保存したquiz.jsonファイルがある状態で、「original_question」が含まれている行を検索します。

% grep original_question quiz.json "original_question": "明治時代に西洋から伝わった「テーブル・ターニング」に起源を持つ占いの一種で、50音表などを記入した紙を置き、参加者全員の人差し指をコインに置いて行うのは何でしょう?" "original_question": "『non・no』『週刊プレイボーイ』『週刊少年ジャンプ』といえば、発行している出版社はどこでしょう?" "original_question": "「パイプスライダー」や「そり立つ壁」などの関門がある、TBS系列で不定期に放送されている視聴者参加型のTV番組は何でしょう?" "original_question": "東京都内では最も古い歴史を持つ寺院でもある、入口にある「雷門」で有名な観光名所は何でしょう?" "original_question": "「鍋についたおこげ」という意味の言葉が語源であるとされる、日本ではマカロニを使ったものが一般的な西洋料理は何でしょう?" "original_question": "よくオムライスの中身としても使われる、細かく切った鶏肉やタマネギとごはんを炒め、トマトケチャップで味付けしたものを何というでしょう?" "original_question": "エペ・フルーレ・サーブルの3種目がある、細長い剣を持って1対1で闘うスポーツは何でしょう?" "original_question": "静岡県では酒粕を使った漬物としてもよく食べられる、握り寿司ではネタとシャリの間に挟まれる香辛料は何でしょう?" "original_question": "アメリカでは朝食の定番となっている、カリカリに焼いたイングリッシュマフィンに、ベーコンとポーチドエッグを乗せた料理は何でしょう?"

検索パターンには正規表現が利用できます。これは以前まとめたので省略。
オプションとして代表的なのは下記。

検索パターンについて

  • -i ・・・大文字と小文字を区別しない。
  • -e ・・・後ろに検索パターンを追加して、OR検索として利用する。
  • -v ・・・マッチ結果を反転させて表示する。

出力書式について

  • -n ・・・行番号を出力に含める。
  • -H ・・・マッチしたファイルのファイル名を出力に含める。
  • -o ・・・行全体ではなく検索パターンにマッチした箇所だけを出力する。

sedコマンドで文字列を置換する

sedコマンドで文字列を置換することができます。
sed [オプション] スクリプト 入力ファイル と入力します。

スクリプトは「アドレス」と「コマンド」の組み合わせで構成されます。

アドレスの指定方法

  • 数字 ・・・指定した行番号の行
  • /正規表現/ ・・・正規表現にマッチする行
  • $ ・・・ 最終行

コマンドの指定方法

  • s ・・・文字列を置換する。 s/検索パターン/置換後文字列/フラグ

フラグ

  • /g・・・グローバルマッチ
  • /i・・・大文字と小文字を区別しない

sedのオプション

  • -e・・・スクリプトを複数指定する
  • -i・・・ファイルを編集して上書き保存する。すぐ後に文字列を指定すると元のファイルのバックアップが作成される。macではバックアップ必須。
    参考:Macの(BSD版)sed での上書き保存