如何包装Python文本流以动态替换字符串?

时间:2017-08-02 19:52:20

标签: python-3.x pandas csv text replace

鉴于我的解决方案似乎有些复杂,我可能做错了。

基本上,我正在尝试在文本流中动态替换字符串(例如open('filename', 'r')io.StringIO(text))。上下文是我试图让pandas.read_csv()将“无限”处理为“inf”而不是窒息它。

我不想在内存中啜饮整个文件(它可能很大,即使生成的DataFrame将存在于内存中,也不需要整个文本文件)。效率是一个问题。因此,我希望继续使用read(size)作为获取文本的主要方式(无readline这是非常慢的)。困难来自read()可能返回一个文本块的情况,这些文本块在我们要替换的字符串之一的中间结束。

无论如何,下面是我到目前为止所得到的。它处理我到目前为止所抛出的条件(行大于大小,在某些读取块的边界处搜索字符串),但我想知道是否有更简单的东西。

哦,顺便说一下,我除了打电话给read()之外别处其他任何事情。

class ReplaceIOFile(io.TextIOBase):
    def __init__(self, iobuffer, old_list, new_list):
        self.iobuffer = iobuffer
        self.old_list = old_list
        self.new_list = new_list
        self.buf0 = ''
        self.buf1 = ''
        self.sub_has_more = True

    def read(self, size=None):
        if size is None:
            size = 2**16
        while len(self.buf0) < size and self.sub_has_more:
            eol = 0
            while eol <= 0:
                txt = self.iobuffer.read(size)
                self.buf1 += txt
                if len(txt) < size:
                    self.sub_has_more = False
                    eol = len(self.buf1) + 1
                else:
                    eol = self.buf1.rfind('\n') + 1
            txt, self.buf1 = self.buf1[:eol], self.buf1[eol:]
            for old, new in zip(self.old_list, self.new_list):
                txt = txt.replace(old, new)
            self.buf0 += txt
        val, self.buf0 = self.buf0[:size], self.buf0[size:]
        return val

示例:

text = """\
name,val
a,1.0
b,2.0
e,+Infinity
f,-inf
"""

size = 4  # or whatever -- I tried 1,2,4,10,100,2**16
with ReplaceIOFile(io.StringIO(text), ['Infinity'], ['inf']) as f:
    while True:
        buf = f.read(size)
        print(buf, end='')
        if len(buf) < size:
            break

输出:

name,val
a,1.0
b,2.0
e,+inf
f,-inf

所以对于我的申请:

# x = pd.read_csv(io.StringIO(text), dtype=dict(val=np.float64))  ## crashes
x = pd.read_csv(ReplaceIOFile(io.StringIO(text), ['Infinity'], ['inf']), dtype=dict(val=np.float64))

输出:

  name       val
0    a  1.000000
1    b  2.000000
2    e       inf
3    f      -inf

0 个答案:

没有答案