我有这个文本文件,我需要将它的某些部分插入到列表中。
该文件如下:
blah blah
.........
item: A,B,C.....AA,BB,CC....
Other: ....
....
我只需要撕掉A,B,C ...... AA,BB,CC .....部件并将它们放入列表中。也就是说,“Item:”之后和“Other:”之前的所有内容
这可以通过小输入轻松完成,但问题是它可能包含大量项目,文本文件可能相当庞大。从算法来讲,使用rfind和strip对于大输入和高输入一样有效吗?
什么是有效的方法呢?
答案 0 :(得分:2)
我认为不需要rfind()
也不需要strip()
。
看起来你只是想做:
start = 'item: '
end = 'Other: '
should_append = False
the_list = []
for line in open('file').readlines():
if line.startswith(start):
data = line[len(start):]
the_list.append(data)
should_append = True
elif line.startswith(end):
should_append = False
break
elif should_append:
the_list.append(line)
print the_list
这不会将整个文件保存在内存中,只是当前行和在开始和结束模式之间找到的行列表。
答案 1 :(得分:0)
要回答有关效率的问题,请仔细阅读文件并逐行比较,以获得净O(n)平均案例表现。
代码示例:
pattern = "item:"
with open("file.txt", 'r') as f:
for line in f:
if line.startswith(pattern):
# You can do what you like with it; split it along whitespace or a character, then put it into a list.
您正在按顺序搜索整个文件,在遇到要查找的元素之前,您必须比较文件中的一些元素。
您可以选择构建搜索树。虽然构建成本为O(n),但搜索时间会花费O(log k n)(总体上会导致O(n)时间),其中k是起始字符的数量你的名单中有。
答案 2 :(得分:0)
这个问题很简单,它实际上只有两个状态,所以你可以使用一个布尔变量来跟踪你在做什么。但是像这样的问题的一般情况是编写一个从一个状态转换到另一个状态的状态机,直到它完成问题为止。
我喜欢将状态用于枚举;不幸的是,Python并没有真正的内置枚举。所以我使用一个带有一些类变量的类来存储枚举。
使用标准Python习惯用法for line in f
(其中f
是打开的文件对象),您可以从文本文件中一次获得一行。这是在Python中处理文件的有效方法;您正在跳过的初始行将被丢弃。然后,当你收集物品时,你只需保留你想要的物品。
这个答案是为了假设“item:”和“Other:”永远不会出现在同一行。如果发生这种情况,您需要编写代码来处理这种情况。
编辑:我将start_code和stop_code作为函数的参数,而不是对示例中的值进行硬编码。
import sys
class States:
pass
States.looking_for_item = 1
States.collecting_input = 2
def get_list_from_file(fname, start_code, stop_code):
lst = []
state = States.looking_for_item
with open(fname, "rt") as f:
for line in f:
l = line.lstrip()
# Don't collect anything until after we find "item:"
if state == States.looking_for_item:
if not l.startswith(start_code):
# Discard input line; stay in same state
continue
else:
# Found item! Advance state and start collecting stuff.
state = States.collecting_input
# chop out start_code
l = l[len(start_code):]
# Collect everything after "item":
# Split on commas to get strings. Strip white-space from
# ends of strings. Append to lst.
lst += [s.strip() for s in l.split(",")]
elif state == States.collecting_input:
if not l.startswith(stop_code):
# Continue collecting input; stay in same state
# Split on commas to get strings. Strip white-space from
# ends of strings. Append to lst.
lst += [s.strip() for s in l.split(",")]
else:
# We found our terminating condition! Don't bother to
# update the state variable, just return lst and we
# are done.
return lst
else:
print("invalid state reached somehow! state: " + str(state))
sys.exit(1)
lst = get_list_from_file(sys.argv[1], "item:", "Other:")
# do something with lst; for now, just print
print(lst)
答案 3 :(得分:0)
虽然我通常会抓住机会使用正则表达式,但我觉得在大文件中只出现一次,使用正则表达式会有更多的工作和计算成本太高。所以也许直截了当的答案(在python中)是最合适的:
s = 'item:'
yourlist = next(line[len(s)+1:].split(',') for line in open("c:\zzz.txt") if line.startswith(s))
当然,这假设'item:'不存在于其他任何未跟随'other:'的行上,但是在'item:'中只存在一次并且在行的开头,这个简单的发电机应该适用于您的目的。
答案 4 :(得分:0)
我写了一个答案,假设起始码和停止码必须出现在一行的开头。这个答案还假设文件中的行相当短。
相反,您可以以块的形式读取文件,并检查块中是否存在起始代码。对于这个简单的检查,您可以使用if code in chunk
(换句话说,使用Python in
运算符来检查包含在另一个字符串中的字符串)。
所以,读取一个块,检查开始代码;如果不存在则丢弃该块。如果存在启动代码,则在搜索停止代码时开始收集块。在最近的Python版本中,您可以使用合理的性能逐个连接块。 (在旧版本的Python中,您应该将块存储在列表中,然后使用.join()
方法将块连接在一起。)
一旦构建了一个字符串,用于保存从开始代码到结束代码的数据,您可以使用.find()
和.rfind()
查找起始代码和结束代码,然后仅删除你想要的数据。
如果启动代码和停止代码可以在文件中出现多次,请将所有上述内容循环并循环,直到达到文件末尾。