Python中是否有`string.split()`的生成器版本?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (65)

string.split()返回一个列表实例。有没有一个版本返回一个生成器呢?是否有任何理由反对使用生成器版本?

提问于
用户回答回答于

很可能会re.finditer使用相当小的内存开销。

def split_iter(string):
    return (x.group(0) for x in re.finditer(r"[A-Za-z']+", string))

演示:

>>> list( split_iter("A programmer's RegEx test.") )
['A', "programmer's", 'RegEx', 'test']

这需要在Python 3.2.1中的不断内存,假设我的测试方法是正确的。我创建了一个非常大的字符串(1GB左右),然后用for循环遍历迭代(不是列表理解,这会产生额外的内存)。这并没有导致内存的显着增长(也就是说,如果内存在增长,则远远低于1GB的内存)。

用户回答回答于

我能想到的最有效的方法是使用方法的offset参数编写一个str.find()。这避免了大量的内存使用,并且在不需要时依赖于正则表达式的开销。

def isplit(source, sep=None, regex=False):
    """
    generator version of str.split()

    :param source:
        source string (unicode or bytes)

    :param sep:
        separator to split on.

    :param regex:
        if True, will treat sep as regular expression.

    :returns:
        generator yielding elements of string.
    """
    if sep is None:
        # mimic default python behavior
        source = source.strip()
        sep = "\\s+"
        if isinstance(source, bytes):
            sep = sep.encode("ascii")
        regex = True
    if regex:
        # version using re.finditer()
        if not hasattr(sep, "finditer"):
            sep = re.compile(sep)
        start = 0
        for m in sep.finditer(source):
            idx = m.start()
            assert idx >= start
            yield source[start:idx]
            start = m.end()
        yield source[start:]
    else:
        # version using str.find(), less overhead than re.finditer()
        sepsize = len(sep)
        start = 0
        while True:
            idx = source.find(sep, start)
            if idx == -1:
                yield source[start:]
                return
            yield source[start:idx]
            start = idx + sepsize

你想怎么用就怎么用...

>>> print list(isplit("abcb","b"))
['a','c','']

虽然每次执行find()或slicing时都会在字符串内寻找一点点成本,但这应该是最小的,因为字符串在内存中表示为continguous数组。

扫码关注云+社区

领取腾讯云代金券