Pythonで文字列からN文字ずつ取り出すジェネレータ

今日djangoでアプリを書いてて、Pythonで文字列からN文字ずつ取り出すのはどうするか?という疑問が出てきたのでちょっと考えて以下のように書いてみました。

# coding=utf-8

import StringIO

text = """ある日の暮方の事である。一人の下人《げにん》が、羅生門《らしょうもん》の下で雨やみを待っていた。
広い門の下には、この男のほかに誰もいない。ただ、所々|丹塗《にぬり》の剥《は》げた、大きな円柱《まるばしら》に、蟋蟀《きりぎりす》が一匹とまっている。羅生門が、朱雀大路《すざくおおじ》にある以上は、この男のほかにも、雨やみをする市女笠《いちめがさ》や揉烏帽子《もみえぼし》が、もう二三人はありそうなものである。それが、この男のほかには誰もいない。
"""
import StringIO

def split_text(text, n):
    if not isinstance(text, unicode):
        text = text.decode('utf-8')
    io = StringIO.StringIO(text)
    while True:
        s = io.read(n)
        if s:
            yield(s)
        else:
            break

for l in split_text(text, 42):
    print l


StringIOのreadを使えばよさそうです。ただstr型だとバイト数で区切られるので、マルチバイト文字が想定される場合はunicode型に変換する必要があります。


実行結果

ある日の暮方の事である。一人の下人《げにん》が、羅生門《らしょうもん》の下で雨やみを
待っていた。
広い門の下には、この男のほかに誰もいない。ただ、所々|丹塗《にぬり》の
剥《は》げた、大きな円柱《まるばしら》に、蟋蟀《きりぎりす》が一匹とまっている。羅生
門が、朱雀大路《すざくおおじ》にある以上は、この男のほかにも、雨やみをする市女笠《い
ちめがさ》や揉烏帽子《もみえぼし》が、もう二三人はありそうなものである。それが、この
男のほかには誰もいない。

追記)

id:Surgoさんからコメントいただきました。

StringIO を使わなくても、文字列のスライスで実現できますよ。

text[0:42], text[42:84] などですね。

なるほど、ということで、スライスで同じ事をやってみました。
こんな感じになりました。

import itertools


def split_text(text, n):
    if not isinstance(text, unicode):
        text = text.decode('utf-8')

        for i in itertools.count():
            s = text[i * n:(i + 1) * n]
            if s:
                yield(s)
            else:
                break

for l in split_text(text, 42):
    print l

itertools.count使ってみたけど、使う必要ないか

def split_text(text, n):
    if not isinstance(text, unicode):
        text = text.decode('utf-8')

        for i in range(0, len(text) / n + 1):
            s = text[i * n:(i + 1) * n]
            if s:
                yield(s)
            else:
                break


for l in split_text(text, 42):
    print l