Pytho io.Stream 試験対策

io.StringIOは、文字列をファイルのように扱うためのクラスである。 このクラスを使うことで、ファイルのように文字列を読み書きすることができる。
重要なところとしてseekというメソッドがある。

seekとは?

seekの意味は、探す、求める、探求する、といった意味がある。
このメソッドは、ファイルの読み書き位置を変更するためのメソッドである。
要するにテキストエディタ等のカーソルのようなものである。
コード上でそれを動かすイメージを想像しながら書くので、ちょっと難しいかもしれない。
試験に出る内容としては、io.StringIOを使って、文字列操作をしたコードが提示され、最終的に出力される文字列を求める問題が出ることがある。
例えば、以下のようなコードが提示されることがある。

import io
 
original = "Hello, World!"
stream = io.StringIO(original)
stream.write("Goodbye, World!")
stream.seek(0)
result = stream.read()
print(result)

# このコードを実行すると、以下のような出力が得られる。

 Goodbye, World!

解説

上書き処理であることに注意

このコードの最初ではio.StringIOを使って、originalという変数をstreamに書き込んでいる。
この場合、streamには"Hello, World!"という文字列が書き込まれている。
次に、stream.write("Goodbye, World!")で、streamに"Goodbye, World!"という文字列を書き込んでいる。
直感的には、"Hello, World!"という文字列がstreamに書き込まれているため、stream.write("Goodbye, World!")で、"Goodbye, World!"という文字列が追加されると考えるかもしれないが、実際には、streamには"Hello, World!"という文字列が書き込まれて、seek(カーソルの位置)の初期位置が0になっているため、
stream.write("Goodbye, World!")で、"Goodbye, World!"という文字列が「上書き」される。

要は、文字の入力形式がinsertモードではなく、overwriteモードであるということであると考えるとわかりやすい。
もしHello, Worldの後ろに追記したいのであれば、以下のようにする必要がある。

import io

original = "Hello, World!"
stream = io.StringIO(original)
stream.seek(0, io.SEEK_END)  # 末尾に移動
stream.write(" Goodbye, World!")  # 末尾に追記
stream.seek(0)
result = stream.read()
print(result)

改行があるようなものを読み込んだ場合どうなるか?

import io

 文字列を用意
text = """Hello, World!
Goodbye, World!
"""

 上記をio.StringIOで読み込む
stream = io.StringIO(text)

 出力してみる
print(stream.read())

# このコードを実行すると、以下のような出力が得られる。

# Hello, World!
# Goodbye, World!

では、この状態で先ほどとおなじように、stream.write("Goodbye, World!")を実行した場合、どうなるか?

import io

 文字列を用意
text = """Hello, World!
Goodbye, World!
"""

 上記をio.StringIOで読み込む
stream = io.StringIO(text)
stream.seek(0, io.SEEK_END)  # 末尾に移動
stream.write("This is New")  # 末尾に追記
stream.seek(0)  # 先頭に移動
result = stream.read()
print(result)

このコードを実行すると、以下のような出力が得られる。

 Hello, World!
 Goodbye, World!
 This is New

解説

「末尾に移動」とは?

「末尾に移動」とは、ファイルの最後に移動することを指す。 各行の末尾ということではないので注意が必要である。 文字列全体での末尾、つまり最後の行の末尾に移動することを指す。

そのため、先ほどのコードでは最終行の後ろに追記された。

じゃあ10行くらいあるような文字列を読み込んで、4行目の末尾に移動するにはどうすればいいか?

import io

 文字列を用意
text = """This is line 1
This is line 2
This is line 3
This is line 4
This is line 5
This is line 6
This is line 7
This is line 8
This is line 9
This is line 10
"""

 上記をio.StringIOで読み込む
stream = io.StringIO(text)

 すべての行を読み込み、行ごとにリストに格納
lines = stream.readlines()

 4行目に文字列を追記(indexは3)
lines[3] = lines[3].strip() + " This is New\n"

 リストを結合して、再度StringIOに戻す
stream = io.StringIO("".join(lines))

結果を表示

stream.seek(0)
result = stream.read()
print(result)

This is line 1
This is line 2
This is line 3
This is line 4 This is New
This is line 5
This is line 6
This is line 7
This is line 8
This is line 9
This is line 10

この記事が気に入ったらサポートをしてみませんか?