お前の記事読んだけど、ファイルコピーしてるだけじゃん。
ふつ~にファイルコピーした方がはえ~し、意味なくね?
ここまでは環境づくりです。これから色々な事が出来るようになるのデス!
上の記事を参考にすれば、既存のテキストファイルを開いて、新しいファイルを作成し、既存ファイルの中身をそのまま書き込む事が出来るようになると思います。
これで読み込んだファイルを色々と編集してから出力する準備は出来ました。
次のステップとして、これから紹介するテキストファイルとPythonソースをベースに、入力ファイルを色々と加工してみましょう。
任意の文字や単語を含む行だけを出力するベースのソースコード
ベースとなるPythonソースコードの途中に条件文を追加する事で、処理結果を色々と変える事が出来るようになります。
ある単語を含む行のみを出力する・しない
ベースソースに1行、条件文を追記すればOKです。print()関数を実行する行のインデントを下げる事を忘れないように注意してください。
ファイルの1行目は必ず出力してから任意の文字を抜き出す方法
このテキストファイルは1行目に項目名が入っているので、必ず出力したくなるかと思います。
やりかたとして簡単に思いつくのは、
- ラインカウンタを持たせて、2行目以上になったら条件判定をする。
- ファイルのシーク位置をずらしてからfor文で回す。
となります。
ラインカウンタを持たせて、2行目以上になったら条件判定をする。
ファイルのシーク位置をずらしてからfor文で回す
ファイルを操作する時は、シーク位置を意識するとより柔軟なプログラムを記述出来るようになります。シーク位置というのは、今現在ファイル全体の何処を指しているのか?という事です。
たとえばファイルを開いた直後のシーク位置は、ファイルの先頭である事が多いでしょう。ただしファイルを開く時に追記のモード引数 “a” を与えた場合、シーク位置はファイルの末尾となります。先頭だと上書きしちゃいますもんね。。
ちなみに
for line in f:
の行が上手く動作するのは、シーク位置が1行づつずれていっているからです。
ここまで見ると、ファイルを1行だけ読みだしてシーク位置を1行だけずらしてから、for文でファイルオブジェクトfへアクセスすれば、上手く動きそうな気がしてきますね。ここで先日紹介したファイルオブジェクトのメソッド readline() を使用します。
2行目でファイルオブジェクトfにreadline() メソッドでアクセスする事で、ファイル1行目の文字列を取り出しています。この時、ファイルのシーク位置は1行移動します。
3行目は、ファイル1行目を代入した変数lineをprint()関数で出力しているだけです。
この実装方法では、動作を制御するカウンタを用意する必要はありません。
ファイルオブジェクトのメソッドreadlines()を使う方法
読み込むファイルサイズが大きくないのであれば、この方法が一番直感的かもしれません。
list型をそのままfor文で回す
2行目でファイルオブジェクトfにreadlines()メソッドでアクセスする事で、ファイルの全行をlist型変数としてlinesへ代入しています。この代入された時に、linesはリスト型となります。
lines[0]にはファイルの1行目、lines[1]にはファイルの2行目・・・というように、ファイルの全行が一気に格納されます。
3行目でファイルの1行目を出力します。
4行目で、ファイルの2行目から最終行までをfor文で回します。lines[1:]という表記は、リストの要素1(ここではファイルの2行目)から最後までを示しています。省略する事で最後までとなります。
lines[1:3]とすれば要素1から3まで、 lines[:3] とすれば 要素0から3まで(lines[0:3]と同じ)、lines[:]とすれば全要素となりますが、これは lines と同じ意味となります。
list型の始まりが0なのは当たり前ですが、終わりが何処なのかは調べないと分からないので、慣れないと面喰いますが、lines[1:] といった省略表記はとても便利です。
list型の要素数を調べて、その回数だけfor文で回す
3行目がぱっと見、1番訳が分からないかと思いますが、分かってしまえばとても簡単です。
len()はPythonの組み込み関数で、色々な型の要素数を返してくれます。len(lines)とすると、linesは4つの要素を含むリスト(元は4行のファイル)なので、4が返されます。
次にrange(len(lines))ですが、上の説明から実際はrange(4)となります。range()はfor文と組みわせる事で簡単にループを作る事が出来るのですが、ここではrange(4)で4回のループが作成されます。そしてループの先頭では、idxに0,1,2,3が代入されます。
まとめ
任意の文字や単語を含む行を出力するだけでしたが、色々なやり方があるんだなというのが伝わったかと思います。他にもやり方は色々とあるので、自分に合ったコードの実装を是非探してみてください。
この記事で示した方法はprint関数での標準出力ですが、このprint関数をファイルオブジェクトのwrite()メソッドに置き換える事で、ファイル出力とする事は簡単です。
最後に今回は単純な文字のマッチングでしたが、もっと厳格かつ柔軟にテキストを処理したい場合には、正規表現(regular expression)を用いることで実現が可能となります。
正規表現は言語に依存しない汎用的な記法なので、テキストの編集する機会が多い方は是非勉強される事をお勧めします。このブログでもいつか紹介したいと考えています。
それでは今日はこの辺で。