【问题标题】:Any way to split python string without generate new strings?有什么方法可以在不生成新字符串的情况下拆分 python 字符串?
【发布时间】:2015-01-18 00:08:51
【问题描述】:

输入的是一个包含大量字符的字符串,我希望将这个字符串拆分成一个带有特殊分隔符的字符串列表。

但我猜想简单地使用split会生成新的字符串,而不是拆分原始输入字符串本身,在这种情况下会消耗大量内存(保证不会再使用原始字符串)。

那么有没有一种方便的方法来进行这种破坏性拆分?

情况如下:

input_string = 'data1 data2 <...> dataN'
output_list = ['data1', 'data2', <...> 'dataN']

我希望 output_list 中的 data1 和 input_string 中的 data1(以及所有其他)共享相同的内存区域。

顺便说一句,对于每个输入字符串,大小为 10MB-20MB;但是因为有很多这样的字符串(大约100个),所以我想这里应该考虑内存消耗?

【问题讨论】:

  • comline = "foo bar" com = commline.split(' ') print(com[0]) 将产生“foo”,因此字符串拆分实际上会生成一个列表。
  • 你的猜测是基于什么?
  • 我认为 split 在 python2 和 python3 中都会生成一个 list
  • "a huge number of characters" -- 我们说的有多大?兆?千兆?
  • @HongxuChen -- 这些天 MB 并不是什么大不了的事。我的建议是.split(),不用担心。您的内存消耗大约会增加一倍——如果字符串为 10-20 Mb,您将使用大约 40 Mb。这几天真的不坏。让垃圾收集器在你有能力的时候进行清理。 :-)

标签: python string


【解决方案1】:

在 Python 中,字符串是不可变的。这意味着任何更改字符串的操作都会创建一个新字符串。如果您担心内存问题(尽管这应该不是什么大问题,除非您正在处理巨大的字符串),您总是可以用新的修改过的字符串覆盖旧字符串,替换它。

您描述的情况有点不同,因为split 的输入是一个字符串,而输出是一个字符串列表。它们是不同的类型。在这种情况下,我只需创建一个包含split 输出的新变量,然后将旧字符串(即拆分函数的输入)设置为None,因为您保证不会再次使用它。

代码:

split_str = input_string.split(delim)
input_string = None

【讨论】:

  • 是否有任何字符串包装器(即mutable字符串)来做字符串修改操作?
  • @HongxuChen Python 中没有可变字符串这种东西。我不知道为什么这对你来说如此重要。你的琴弦有多大?
  • @AdamSmith 大约 10-20MB;我真的需要考虑内存消耗吗?
【解决方案2】:

唯一的选择是使用切片而不是split 来访问子字符串。您可以使用str.find 来查找每个分隔符的位置。然而,这会很慢,而且很繁琐。如果您可以使用 split 并使原始字符串超出范围,那么这将是值得的。

你说这个字符串是输入的,所以你可能想考虑读取更少的字符,这样你就可以处理更易于管理的块。你真的需要同时在内存中的所有数据吗?

【讨论】:

  • 我不需要同时所有的数据,但应该可以用于以后的迭代。
【解决方案3】:

也许 Pythonic 的方式是使用迭代器?这样,新的子字符串一次只能在内存中一个。基于 Splitting a string into an iterator

import re
string_long = "my_string " * 100000000 # takes some memory
# strings_split = string_long.split()  # takes too much memory
strings_reiter = re.finditer("(\S*)\s*", string_long) # takes no memory
for match in strings_reiter:
    print match.group()

这很好用,不会导致内存问题。

【讨论】:

    【解决方案4】:

    如果您正在谈论的字符串太大以至于您无法忍受将它们放入内存中,那么可能会遍历字符串一次(O(n),使用str.find 可能会改进但我不是当然)然后存储一个包含slice 对象的生成器会更节省内存?

    long_string = "abc,def,ghi,jkl,mno,pqr" # ad nauseum
    splitters = [','] # add whatever you want to split by
    marks = [i for i,ch in enumerate(long_string) if ch in splitters]
    slices = []
    start = 0
    for end in marks:
        slices.append(slice(start,end))
        start = end+1
    else:
        slices.append(slice(start,None))
    
    split_string = (long_string[slice_] for slice_ in slices)
    

    【讨论】:

    • 我从来没有找到使用它的机会,但也许mmap 也会有所帮助......
    猜你喜欢
    • 2013-05-10
    • 2015-05-26
    • 2020-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多