Pythonでフォーマットして文字列出力
目次
フォーマットして文字列出力
PHP sprintf
<?php $str = sprintf('今日は%s、明日は%s', '晴れ', '曇り'); echo $str; // 今日は晴れ、明日は曇り $str = sprintf('今日は%1$s、明日も%1$s', '晴れ'); echo $str; // 今日は晴れ、明日も晴れ $str = sprintf('%.2f', 1 / 3); echo $str; // 0.33 $str = sprintf('%04d', 12); echo $str; // 0012 $str = sprintf('%1$04d, %1$08d', 12); echo $str; // 0012, 00000012
直接出力する場合は printf
を使用できます。
Python %演算子
2.x 3.x
# -*- coding: utf-8 -*- str = u'今日は%s、明日は%s' % (u'晴れ', u'曇り') print(str) # 今日は晴れ、明日は曇り str = u'今日は%(weather)s、明日も%(weather)s' % {'weather': u'晴れ'} print(str) # 今日は晴れ、明日も晴れ str = '%.2f' % (1.0 / 3.0) print(str) # 0.33 str = '%04d' % 12 print(str) # 0012 str = '%(i)04d, %(i)08d' % {'i': 12} print(str) # 0012, 00000012
Pythonで末尾の改行だけ取り除く
ファイルから読み込んだ時など、末尾にある改行だけ取り除きたい場合があります。
末尾の1文字だけ取り除くと改行以外の文字が取り除かれてしまう恐れがありますね。
この場合Pythonではどのように行うのか調べてみました。
目次
末尾の改行だけ取り除く
いずれもstringとスペースは残り、字数9となり、末尾の改行(\r
or \n
)だけが取り除かれます。
※\r\n
はWindows、\n
はLinux、\r
は旧Mac。
PHP rtrim
<?php echo strlen(rtrim("string \r\n\r\n", "\r\n")); echo strlen(rtrim("string \n\n", "\r\n")); echo strlen(rtrim("string \r\r", "\r\n"));
Python rstrip
2.x 3.x
print(len('string \r\n\r\n'.rstrip('\r\n'))) print(len('string \r\r'.rstrip('\r\n'))) print(len('string \n\n'.rstrip('\r\n')))
Pythonは文字列をスライス表記で操作できるので次のようなことが可能ですが、末尾が文字列でない場合も取り除いてしまうため注意が必要です。
s = 'string \n' print(s[:-1]) # string s = 'string' print(s[:-1]) # strin
こちらを参考にしました。
PHPで言うところのltrim
, trim
, rtrim
が、
Pythonではlstrip
, strip
, rstrip
で利用できるようです。
Pythonで複数の値を複数の変数に同時に代入する
PHPでは見慣れない感じでしたのでメモとして残します。
左辺に複数の変数、右辺に同数の値を記載して代入
a, b = 1, 2 print(a) # 1 print(b) # 2
これはタプルのパックとシーケンスのアンパックを組み合わせたものとのことです。
http://docs.python.jp/2/tutorial/datastructures.html#tuples-and-sequences
http://docs.python.jp/3/tutorial/datastructures.html#tuples-and-sequences
PHPで似たようなことをしようとすると、
<?php list($a, $b) = [1, 2]; echo $a; // 1 echo $b; // 2
※複数の値を配列として返すfunctionからの返り値を受け取る場合などに利用できるかと思われます。
配列の途中の値をまとめて置き換え
スライスで行えます。
v = range(1, 10) print(v) # [1, 2, 3, 4, 5, 6, 7, 8, 9] v[1:6] = ['a'] * 5 print(v) # [1, 'a', 'a', 'a', 'a', 'a', 7, 8, 9]
v[1:6]
の:
の左側のoffset以上:
の右側のoffset未満と覚えることにします。
PHPで行うと、
<?php $v = range(1, 9); print_r($v); /* Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 [5] => 6 [6] => 7 [7] => 8 [8] => 9 ) */ array_splice($v, 1, 5, array_fill(0, 5, 'a')); print_r($v); /* Array ( [0] => 1 [1] => a [2] => a [3] => a [4] => a [5] => a [6] => 7 [7] => 8 [8] => 9 ) */
array_splice
の第1引数で指定する配列はリファレンス渡し
になるので渡した配列そのものが書き換えられます。
Pythonで文字列を1文字ずつ分割する
シングルバイト文字の場合こちらのサイトを参考に解決しましたが、
マルチバイト文字ではどうなるのか疑問が生じたので方法を調べてみました。
目次
文字列を1文字ずつ分割する
PHP preg_split
普段はPHPを利用していますので、参考までにPHPではpreg_split
で行えることを記載します。
シングルバイト文字
<?php $chars = preg_split('//', 'abcdef', -1, PREG_SPLIT_NO_EMPTY); print_r($chars); /* Array ( [0] => a [1] => b [2] => c [3] => d [4] => e [5] => f ) */
マルチバイト文字(UTF-8)
<?php $chars = preg_split('//u', 'あいうえお', -1, PREG_SPLIT_NO_EMPTY); print_r($chars); /* Array ( [0] => あ [1] => い [2] => う [3] => え [4] => お ) */
Python
2系も3系もlist
を用いることで文字列を分割できる模様。
2系と3系でマルチバイト文字の取り扱いが少々異なるようです。
Python 2.x list
シングルバイト文字
chars = list('abcdef') print chars # ['a', 'b', 'c', 'd', 'e', 'f']
マルチバイト文字(UTF-8)
Python 2系では明示的にUnicode文字をあらわすu''
としないと1byteずつ分割される模様。
- list('あいうえお')
# -*- coding: utf-8 -*- chars = list('あいうえお') print chars # ['\xe3', '\x81', '\x82', '\xe3', '\x81', '\x84', '\xe3', '\x81', '\x86', '\xe3', '\x81', '\x88', '\xe3', '\x81', '\x8a']
- list(u'あいうえお')
# -*- coding: utf-8 -*- chars = list(u'あいうえお') chars = [char.encode('utf-8') for char in chars] print str(chars).decode('string-escape') # ['あ', 'い', 'う', 'え', 'お'] for c in chars: print c # あ # い # う # え # お
Python 3.x list
シングルバイト文字
chars = list('abcdef') print(chars) # ['a', 'b', 'c', 'd', 'e', 'f']
マルチバイト文字(UTF-8)
※Windows7コマンドプロンプトで素直にprintしたところ期待するUTF-8ではなくShift_JISに変換されてしまいました。
- これを避けるため、当初UTF-8のbytes型に変換した上sysモジュール経由で出力。
# -*- coding: utf-8 -*- import sys chars = list('あいうえお') chars = [bytes(char, 'utf-8') for char in chars] sys.stdout.buffer.writelines(chars) # あいうえお for char in chars: sys.stdout.buffer.write(char) sys.stdout.write('\n') sys.stdout.flush() # あ # い # う # え # お
- しかし、この現象はencodingの設定により起こるとのこと。
当初の初期値。
print(sys.getdefaultencoding()) # utf-8 print(sys.stdout.encoding) # 出力がutf-8ではない # cp932
- 次の記事を参考に適切な文字コードを
sys.stdout.encoding
に設定したところprintでもできました。
# -*- coding: utf-8 -*- import sys, io sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') chars = list('あいうえお') print(chars) # ['あ', 'い', 'う', 'え', 'お'] for char in chars: print(char) # あ # い # う # え # お
PHPerがPython 2.7でタブ区切りファイル(TSV)を読み込んで処理した際のメモ
普段プログラミング言語はPHPを主に使用していますが、Python 2.7を使用する機会があったためメモを残します。
コマンドラインで実行する形式で行ったため、コマンドライン引数、引数に指定されたファイルの存在確認、ファイルを開く、読み取るなどの関数や処理をPHPなら~、Python 2.7なら~という形式でメモしています。
目次
- 目次
- コマンドライン引数
- ファイルの存在確認
- ファイルを開く
- 文字列を分割する
- 配列のスライス
- ファイルに書き込む
- 異なる型の値を含む配列/リストをjoinして出力
- コマンドライン引数に指定のTSVファイルを読み込み何かしら処理する例
コマンドライン引数
PHPもPython 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 fopen
や file_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: # 何かしら処理