PHPerがPython 2.7でタブ区切りファイル(TSV)を読み込んで処理した際のメモ

普段プログラミング言語PHPを主に使用していますが、Python 2.7を使用する機会があったためメモを残します。

コマンドラインで実行する形式で行ったため、コマンドライン引数、引数に指定されたファイルの存在確認、ファイルを開く、読み取るなどの関数や処理をPHPなら~、Python 2.7なら~という形式でメモしています。

目次

コマンドライン引数

PHPPython 2.7も始めの要素にはスクリプトパスが入っている。

PHP $argv

if ($argc < 2) {
    exit('引数が足りません。');
}
print_r($argv);

Python 2.7 sys.argv

import sys
if len(sys.argv) < 2:
    sys.exit('引数が足りません。')
print sys.argv

ファイルの存在確認

PHP file_exists

if (!file_exists($argv[1])) {
    exit(sprintf('%s does not exist', $argv[1]));
}

Python 2.7 os.path.exists

import sys
import os.path
if not os.path.exists(sys.argv[1]):
    sys.exit('%s does not exist' % sys.argv[1])

ファイルを開く

PHP fopenfile_get_contents を使うと思います。

  • fopen
$fh = fopen($filename, 'r');
fclose($fh);
  • エラーハンドリングもする
$fh = fopen($filename, 'r');
if (!$fh) {
    exit($filename . 'を開けませんでした。');
}
fclose($fh);
  • file_get_contents
$string = file_get_contents($filename);

Python 2.7 open を使えますが、ファイルの読み込みなら with 構文をあわせて利用すると、ファイルの閉じ忘れがなくなり便利そうです。

  • with 構文を利用する open
with open(filename, 'r') as fh:
  • with 構文を利用しない場合は使い終わった後に閉じます。
fh = open(filename, 'r')
fh.close()
  • エラーハンドリングもする
import sys
fh = None
try:
    fh = open(filename, 'r')
except IOError as e:
    sys.exit('%sを開けませんでした。' % filename)
fh.close()

文字列を分割する

タブで分割する場合。
PHP\t をタブとして用いる場合ダブルクォーテーションの必要がありますが、Pythonではシングルクォーテーションとダブルクォーテーションの区別がないようです。

PHP explode

$words = explode("\t", $row);

Python 2.7 split

words = row.split('\t')

配列のスライス

PHP array_slice

$row = ['a', 'b', 'c'];
$words = array_slice($row, 0, -1);
print_r($words);
/*
Array
(
    [0] => a
    [1] => b
)
*/

Python 2.7 スライス表記というものがあるようです。

row = ['a', 'b', 'c']
words = row[:-1]
print words
# ['a', 'b']

ファイルに書き込む

PHP fwrite

fwrite($fh, '文字列');

Python 2.7 write, writelines

fh.write('文字列');
words = ['文', '字', '列']
fh.writelines(words);

異なる型の値を含む配列/リストをjoinして出力

PHPだと型を気にせずに implode で連結することが出来るところ、Python 2.7だと TypeError: sequence item 0: expected string, int found というエラーが発生して動作しなかったときの対処。

例えば id(int), name(string), created(string) というような配列/リストがあったとき、

PHP implode

$row = [123, 'name', date('Y-m-d H:i:s')];
print_r(implode("\t", $row));
// 123 name 2016-09-27 00:45:12

Python 2.7 join

import datetime
row = [123, 'name', datetime.datetime.now()]
print '\t'.join(row)
# TypeError: sequence item 0: expected string, int found

Python 2.7でTypeError発生。
調べたところstringにconvertすると良い模様。
http://stackoverflow.com/questions/5618878/how-to-convert-list-to-string

import datetime
row = [123, 'name', datetime.datetime.now()]
print '\t'.join(str(col) for col in row)
# 123 name 2016-09-27 00:45:12.804000

コマンドライン引数に指定のTSVファイルを読み込み何かしら処理する例

PHP fgetcsv

if ($argc != 2) {
    exit('1つ目の引数にはTSVファイルを指定してください。');
}

if (!file_exists($argv[1])) {
    exit(sprintf('%s does not exist', $argv[1]));
}

if (($csvfile = fopen($argv[1], 'r')) !== false) {
    while (($columns = fgetcsv($csvfile, 0, "\t")) !== false) {
        // 何かしら処理
    }
    fclose($csvfile);
}

Python 2.7 csvモジュール

# coding: utf-8
import sys
if len(sys.argv) != 2:
    sys.exit('1つ目の引数にはTSVファイルを指定してください。')

import os.path
if not os.path.exists(sys.argv[1]):
    sys.exit('%s does not exist' % sys.argv[1])

import csv
with open(sys.argv[1], 'r') as csvfile:
    reader = csv.reader(csvfile, delimiter='\t')
    for columns in reader:
        # 何かしら処理