Python Baby Names Exercise in Japanese

Google による Python の授業 (日本語訳)/ Google's Python Class (英語原文)

資料
日本語訳: 設定/ 入門/ 文字列/ リスト/ 整列/ 辞書とファイル/ 正規表現/ ユーティリティ
英語原文: Set Up/ Introduction/ Strings/ Lists/ Sorting/ Dict and Files/ Reg. Exp./ Utilities

練習問題
日本語訳: 基本問題/ 新生児名 / 特殊なコピー/ アクセス履歴のパズル
英語原文: Basic Exercises/ Baby Names Exercise/ Copy Special Exercise/ Log Puzzle Exercise

講義映像
英語
1日目: Introduction, Strings/ Lists and Sorting/ Dicts and Files
2日目: Regular Expression/ Utilities/ Utilities urllib/ Conclusions

新生児の名前に関する Python の練習問題


社会保障局は, 年ごとに アメリカでその年に生まれた新生児の名前で多かったものを 記録したデータを持っています (社会保障局新生児名 を参照).
この練習問題に対するファイルは google-python-exercises の中の "babynames" ディレクトリの中にあります. (google-python-exercises.zip をまだダウンロードしていないなら, ダウンロードして, 詳しくは Set Up (英語原文), 設定 (日本語訳) を見ること). babynames.py にコードを書き加えること. baby1990.html baby1992.html ... といったファイルは 上の社会保障局のサイトにいくと得られるものと同様の生の html が入っています. その html を見て, そこからデータを抜き取る方法を考えること.

Part A


babynames.py ファイルの中に, baby1990.html といったファイル名を引数に取り, 単一のリストとしてファイルからのデータを返す, extract_names(filename) 関数を実装すること. 返されるリストは, 年の文字列で始まるリストで, アルファベット順の 名前と順位からなる文字列が続きます. ['2006', 'Aaliyah 91', 'Abagail 895', 'Aaron 57', ...]. main() が extract_names() 関数を呼び, extract_names() 関数が返す値を出力するように, main() を修正すること. (main はすでに コマンドラインの引数の文字解析に対する コードを持っています. ) 年とそれぞれの名前に対する正規表現で詰まったときのために, 答えとなる正規表現のパターンが この文章の最後に示されています.
男の子と女の子の名前を別々に扱うのではなく, 塊として扱います. いくつかの年では, ある名前が html の中に複数回出てきますが, ここでは 1つの名前に 対して 1つの数字だけを使います. 選択問題: この場合に対応できるように, 最も小さい番号を選ぶアルゴリズムにする.
小さい目標の連なりとしてプログラムを作ること. そのとき, 各段階での作業をしっかり終えてから 次の段階に進むこと. 経験のあるプログラマというのは, 巨大な一段階でプログラム全体を作るのではなく, 徐々に達成して完成に到達する一連の目標を立てています. そのとき, 各段階ではその段階での実行内容を確認できるように 何か出力させています.
ある目標の最後で持っているデータを出力すると, その次の目標に対してデータをどのように再構成するかを考えやすくなります. Python はこのような追加的な開発様式に良くあっています. 例えば, まず年を抽出して出力し, sys.exit(0) を呼ぶ, という 段階を完成させます. 参考まで, 次にいくつかの目標を示します.
  • ファイル中のすべてのテキストを抽出し, 出力する.
  • 年を見つけ, 抽出し, 出力する.
  • 名前と順位を抽出し, 出力する.
  • 名前のデータを辞書に入れ, 出力する.
  • [年, '名前 順位', ...] のリストを作り, 出力する.
  • ExtractNames によるリストを使うように main() を変更する.

これまで, 標準出力に出力する関数を使ってきました. 抽出したデータを *戻り値として返す* 関数の方が, より再利用しやすく, それにより呼び出す側は返されたデータを出力するか, そのデータを使って何か別のことをするか, を選べるようになります (開発中に試している段階では, 自分で書いた関数の中から直接実行状況を表示しても構いません).
それぞれのコマンドラインの引数に対して, main() に extract_names() を呼ばせて, テキストのまとめを表示させること. リストを十分見やすいまとめのテキストに するためには, join が使えます. text = '\n'.join(list) + '\n'
それぞれのファイルに対して, まとめのテキストは次のようになります.
2006
Aaliyah 91
Aaron 57
Abagail 895
Abbey 695
Abbie 650
...

Part B


テキストを標準出力に表示する代わりに, テキストを含むファイルを作りたい場合を考えます. --summaryfile というフラグがあるときは, 次の処理を行います. 入力ファイル 'foo.html' に対して, 標準出力に表示する代わりに, そのファイルのまとめの文章が入った新しいファイル 'foo.html.summary' を作ります.
属性 --summaryfile が与えられたとき,
"./babynames.py --summaryfile baby*.html"
のように * で指定されたすべてのファイルに対しては, プログラムは次のように動作します. この場合, 指定されたファイルすべてに 対するまとめを 1段階で生成します. (シェルの基本的な振る舞いは, シェルが "baby*.html" のパターンを ファイル名と一致するリストに展開し, シェルは babynames.py を実行します. すべてのファイル名はリスト sys.argv に渡されます. )
まとめファイルに入ったデータを使うと, シェルコマンドにより 年ごとのパターンを見ることが出来ます.
$ grep 'Trinity ' *.summary
$ grep 'Nick ' *.summary
$ grep 'Miguel ' *.summary
$ grep 'Emily ' *.summary

正規表現のヒント (訳注: 白色文字で書いているので, 反転するとヒントが見られます.)
年: r'Popularity\sin\s(\d\d\d\d)' 名前: r'<td>(\d+)</td><td>(\w+)</td>\<td>(\w+)</td>'

この資料は Google の Nick Parlante によって作成されたものの翻訳です. Google による Python の授業の文章と映像は Creative Commons Attribution 2.5 ライセンスの下で利用できます.