はてだBlog(仮称)

私的なブログど真ん中のつもりでしたが、気づけばWebサイト系のアプリケーション開発周りで感じたこと寄りの自分メモなどをつれづれ述べています。2020年6月現在、Elasticsearch、pandas、CMSなどに関する話題が多めです。...ですが、だんだんとより私的なプログラムのスニペット置き場になりつつあります。ブログで述べている内容は所属組織で販売している製品などに関するものではなく、また所属する組織の見解を代表するものではありません。

Pythonのopen関数での改行の扱い備忘録(newlineオプション、readlines、readline...)

Pythonのopen組み込み関数では、「改行」に関して「優しい」仕様になっています。

しかし、私のような日曜プログラマは半年に1回ぐらいやっちまうのですが、稀にこの気遣い仕様を忘れて、ハマってしまうこともあるので、ここに備忘録として記しておきます。

まず、open 関数と、改行の振る舞いを制御するnewline引数については次のとおりです。

https://docs.python.org/ja/3/library/functions.html#open

※独り言:Pythonの公式サイトのリファレンスは、比較的ググラビリティが低い感じがする。

open組み込み関数のnewlineオプションの動作確認

公式リファレンスにしっかり書いてあるのですが、いかんせん忘れがちな挙動があります。

まずは、確認用スクリプト

for nl in  [None,'\r\n','\n','\r','']:
    lines = open('kaigyo.txt','r',encoding='utf-8',newline=nl).readlines()
    print('')
    print(f'newline={repr(nl)}')
    print(lines)

newline=None (newlineを指定しない場合。つまりデフォルト。)

改行っぽいやつを改行とみなして扱う。readlines()では、その環境の改行(os.linesep)に置き換えられたものが得られる。 (「ユニバーサル改行モード」と呼ぶらしい)

たまにこれの存在を忘れていて、荒れた改行コードのファイルを解析する時に落とし穴にハマっってしまう。

newline='\n' または '\r\n' または '\r'

指定のもののみ改行とみなして、readlines()でリストとして読み込む。特に改行の標準化などは行わない(元の入力のまま)。

newline=''

改行っぽいやつを改行とみなして扱う。readlines()では、元の入力のままの値が得られる。

IPythonでの確認

In [19]: ! echo -e "a,b,c\nd,e,f\r\ng,h,i\rj,kl" > kaigyo.txt        

In [20]: ! od -x kaigyo.txt 
    ...:                                                                                                                                                                   
0000000      2c61    2c62    0a63    2c64    2c65    0d66    670a    682c
0000020      692c    6a0d    6b2c    0a6c                                
0000030

In [21]: for nl in  [None,'\r\n','\n','\r','']: 
    ...:     lines = open('kaigyo.txt','r',encoding='utf-8',newline=nl).readlines() 
    ...:     print(f'newline={repr(nl)}') 
    ...:     print(lines) 
    ...:                                                                                                                                                                   
newline=None
['a,b,c\n', 'd,e,f\n', 'g,h,i\n', 'j,kl\n']  
※ \r\n  \r単独 \n単独の全てが改行として扱われる。readlines()では、筆者の環境では「\n」に標準化。

newline='\r\n'
['a,b,c\nd,e,f\r\n', 'g,h,i\rj,kl\n']
※ \r\nが改行扱い

newline='\n'
['a,b,c\n', 'd,e,f\r\n', 'g,h,i\rj,kl\n']
※\nが改行扱い

newline='\r'
['a,b,c\nd,e,f\r', '\ng,h,i\r', 'j,kl\n']
※\rが改行扱い

newline=''
['a,b,c\n', 'd,e,f\r\n', 'g,h,i\r', 'j,kl\n']
※改行っぽいやつは改行扱いされ、かつ標準化はしない。