【问题标题】:Can't find string in text file在文本文件中找不到字符串
【发布时间】:2016-03-08 18:07:49
【问题描述】:

给定一个项目编号列表,我正在尝试搜索包含最近项目编号列表的文本文件,并在此最近列表中识别任何内容。然后我想添加最近列表中尚未包含的任何项目。

我的代码在下面,它似乎没有在文本文件中找到任何内容。为什么它不起作用?

def filter_recent_items(items):
    recentitems = []
    with open('last 600 items.txt', 'r+') as f:
        for item in items:
            if item['ID'] in f:
                print 'In! --', item['ID']
            else:
                recentitems.append(item['ID'])
                print 'Out ---', item['ID']
        for item in recentitems:
            f.write("%s\n" % item)


items = [ {'ID': 1}, {'ID': 'test2'} ]     
filter_recent_items(items)

例如,我的文本文件是:

test2

test1

1

但上面的代码返回

Out --- 1
Out --- test2

【问题讨论】:

  • if item['ID'] in f 并没有按照你的想法去做。

标签: python string file python-2.7 search


【解决方案1】:

问题在于您如何检查指定文本是否存在。在您的代码中,f 是一个文件对象,用于读取和写入文件。所以当你检查是否

str in f

它不是在检查你认为它是什么。 (详情见下文。)

相反,您需要读入文件的行,然后遍历这些行并检查必要的字符串。例如。

with open('last 600 items.txt', 'r+') as f:
    lines = f.readlines()
    for l in lines:
        # check within each line for the presence of the items

在上面的代码摘录中,f.readlines() 使用文件对象读取文件的内容并返回一个字符串列表,即文件中的行。

已编辑(感谢 Peter Wood)

Python Membership Details

在 Python 中,当您使用语法 x in y 时,它会检查两件事:

案例1:首先检查y是否有__contains__(b)方法。如果是,则返回y.__contains__(x) 的结果。

案例 2: 但是,如果 y 确实 没有 具有 __contains__ 方法,但确实定义了 __iter__ 方法,则 Python 改为使用 该方法迭代y 的内容并返回True,如果在任何时候被迭代的值之一等于x。否则返回False

如果我们以您的代码为例,在某个时刻,它正在检查语句"test2" in f 的真实性。这里ffile 类型的对象。 (Python File Object Description)。文件对象属于情况 2(即它们没有__contains__,它们__iter__

因此,代码将遍历每一行并查看您的输入字符串是否等于文件中的任何行。由于每一行都以字符 \n 结尾,因此您的字符串永远不会返回 True

详细说明,虽然"test2" in "test2\n" 将返回True,但这里实际执行的测试是:"test2" == "test2\n",即False

您可以手动测试它在您的文件上的工作方式。例如,如果我们想查看"test2" in f 是否应该返回True

with open(filename) as f:
    x = iter(f)
    while(True):
        try:
            line = x.next()
        except:
            break
        print(line)
        print(line == "test2")

您会注意到它打印出每一行(包括末尾的换行符)并且line == "test2" 的结果始终是False

如果我们尝试:"test2\n" in f,结果将是True

结束编辑

【讨论】:

  • 'test2\n' in fTrue
  • membership test detailsin 将使用iter,因为file 没有定义__contains__,但定义了__iter__。它将迭代,直到全部用完或找到匹配项。 iter 会从文件中返回一行,所以'test2\n' 会匹配,而'test2' 不会。
  • 为了清楚起见,它必须是完全匹配的。从链接中:x in y 为真,如果在迭代 y 时产生了带有 x == z 的某个值 z
  • 哦,这很有趣,我没有意识到这一点。我正要问为什么当"test2" in "test2\n" 返回True 时它不会返回部分匹配,但你只是回答了它。谢谢,我会在我的帖子中添加一个编辑。
【解决方案2】:

打印出您的数据存储,f。首先,我希望您嵌入了阻止项目匹配的换行符:“1”不匹配“1\n”。其次,请注意 **with open" 为您提供了一个生成器,而不是列表或元组。您不能多次扫描列表。除非您以某种方式遍历它,否则您不会获得其中的数据。

你需要代码把所有的元素都存入内存,比如

content = f.read().split("\n")
for item in items:
    if item["ID" in content:

【讨论】:

  • 另外,字典列表真的是您想要输入的吗?我认为一个简单的列表就可以了,例如 [1, "item2"]
【解决方案3】:

正如其他人所说,if "somestring" in f 总是会失败。 f 是一个文件对象,当您对其进行迭代时,它会生成文本行。这些 LINES 中的一个或多个可能包含您的文本,因此您可以这样做:

if any("targetstring" in line for line in f):
    # success

f.read()f.readlines() 方法相比,这可以节省内存,这两种方法都会在执行任何操作之前将整个文件流式传输到内存中。

@PeterWood 在 cmets 中指出,您的一些目标字符串实际上并不是字符串。你也应该注意这一点。 all(isinstance(item["ID"], str) for item in items) 应该是 True

【讨论】:

  • 另外,第一个item['ID']int
猜你喜欢
  • 2015-04-04
  • 1970-01-01
  • 2015-07-14
  • 1970-01-01
  • 2015-02-02
  • 1970-01-01
  • 2021-12-24
  • 2013-04-18
相关资源
最近更新 更多