やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Pythonのreadline()は改行コードも含まれてしまう

Pythonで1行ずつ処理したいときに不便。

改行コードが含まれる"1行毎の取得"って…

with open('./file.txt', mode='r', encoding='utf-8') as f:
    line = f.readline()

なんとlineには改行コードも含まれてしまう。

ふつうに考えれば、1行毎に処理するのだから改行コードが欲しいとは思えない。なぜこのような仕様なのか謎。

pythonでファイルを読み込んで改行を消す【ファイル読み込みの注意点】 - Qiita

改行コードが邪魔なので削除しようとするも、確実に末尾の改行コードを削除するのが難しい。

解法

 追記:2019-09-27。

import os
str.rstrip(os.linesep)

 末尾に改行を含む文字列strに対して、OS固有の改行コードを削除する。

改行コードを削除する難しさ

改行コードはOSごとに異なる

OS|改行コード --|---------- Windows|\r\n Mac\r Linux|\n

[:-1]

line[:-1]とすると最後の1字を削除できる。

  • 最終行に改行がなかった場合に1字削られてしまう
  • \r\nの場合、\rが残る

「最後の文字が改行コードである場合は削除する」という条件付きにしたい。

replace('\n', '')

  • 最後の文字にかぎらずすべての\nを削除してしまう

pythonでファイルを読み込んで改行を消す【ファイル読み込みの注意点】 - Qiita

OSによる違いがあるから、以下のようにせねば削除できない。

text = text.replace('\r','')
text = text.replace('\n','')

rstrip([chars])

組み込み型 — Python 3.7.4 ドキュメント

>>> 'mississippi'.rstrip('ipz')
'mississ'

上記は末尾のippiが削除されている。コードの字面からは連想できない結果に見える。最後の1文字がi,p,zのいずれかであれば削除する。削除後の1字を見ていく。i,p,zのいずれかであれば削除する。これをくりかえす。i,p,zのいずれでもないならそこで削除を終了する。

これ、わかりにくくて危険な気がする。末尾の文字列がipzに一致しているなら、その部分を削除するわけではない。Pythonは文字型と文字列型の表現に違いがないからわかりにくい。C言語みたく文字は'a', 文字列は"abc"のような違いがあれば、少しはわかりやすいのだが。

text.rstrip('\n')

上記の場合は末尾の\nを全て削除する。1つだけ削除することはできない。\nが続いている限り、すべて削除する。

text.rstrip('\r\n')

上記の場合、最後の文字が\rまたは\nであるかぎり1文字ずつ削除しつづける。末尾の\r\nを削除するわけではない。

後者だと誤解してしまう可能性は否めない。

1行データを取得する

わかりにくいものの組合せ。

line = f.readline().rstrip('\r\n')
  • f.readline()で1行ごとに取得するっぽく読めるのにrstrip('\r\n')で改行コードを削除しているっぽく読める

冗長。f.readline()だけで改行なしにしてくれればコードの字面どおりに読めて何の問題もなかったのに。

print()関数でも改行されてしまうし、どうにも気に食わない。わざとわかりにくく不便にしているのかと疑ってしまう。

所感

C#String.TrimEnd('\r', '\n')のように書くと末尾を消せる。末尾にある"文字"を削除することがわかりやすい。

Pythonには文字と文字列の区別がないため仕方ないのか。そういうものとして覚えるしかない。