【问题标题】:Appending into a dictionary within a loop - strange behavior在循环中附加到字典中 - 奇怪的行为
【发布时间】:2019-01-04 06:52:03
【问题描述】:

这可能听起来平淡无奇,但确实很痛苦。 所以我编写了解析行的代码。 .txt 文件有一行与我的 re.match 匹配,另一行不匹配。

cat file.txt
00.00.00 :  Blabla
x

在这种情况下,我会检查第一个字母“x”。

def parser():
path = "file.txt"
with open (path, 'r+') as file:
msg = {}
list = []
start = 0
   lines = file.readlines() 
   for i in range (0,len(lines)):
        line = lines[i]

        if re.match('MY RULES', line) is not None:
                field['date'] = line[:8]
                msg['msg'] = line[start + 2:]
                print msg
                if line.startswith('x'):
                    msg['msg'] += line

        list.append(msg)

    print chat

输出 2 行

{'date': '0.0.00', 'msg': 'BlaBla'}
{'msg': 'x'}

问题是我不能将第二个 dict message['msg'] 附加到最后一条消息,如果以“x”开头。

预期的输出是:

 {'date': '0.0.00', 'msg': 'BlaBlax'}

我尝试使用变体来更改最后附加的聊天:

        else:

        list[len(list) - 1]['msg'] += + line

但后来我得到了错误: IndexError: 列表索引超出范围

我也尝试使用 next(infile) 来预测下一行,但它每隔一行输出一次。

你会如何欺骗一个嵌套循环来附加一个 dict 条目?

干杯

【问题讨论】:

  • 请修正缩进。目前,只有在匹配成功时才能处理带有“x”的行。这与您的预期结果不符。
  • 也许 ` 如果 re.match('MY RULES', line) 不是 None:` 这不会让它通过添加 x as msg 来传递到行中
  • 你总是有一对(date, message)吗?在这种情况下,您可以阅读整个文件并执行str.split(':')
  • @guidot:这就是重点。如果我在同一级别缩进 f,它将输出 msg['msg'] 作为单个值。前任。 {'date': '0.0.00', 'msg': 'BlaBla'} {'msg': 'x'} ------- 我想将它附加到之前匹配的字典中。
  • @harshil9968:评论“不是无”会影响结果。

标签: python list loops dictionary append


【解决方案1】:

首先不要使用list 作为变量的名称,因为它是内置关键字并且你正在隐藏它。

其次,如果我理解正确,您想附加最后一个结果。

这里:

if re.match('MY RULES', line) is not None:
                field['date'] = line[:8]
                msg['msg'] = line[start + 2:]
                print msg
                if line.startswith('x'):
                    msg['msg'] += line

您正在分析同一行,并且此 msg['msg'] = line[start + 2:] 在下一次迭代中会覆盖您在字典 msg 中的键 msg 并清除先前的值。所以这段代码

 field['date'] = line[:8]
 msg['msg'] = line[start + 2:]
 print msg

即使对于输入文件中的简单x,也始终会执行并清除键msg 下的先前值

如果您希望它工作,则需要 if else,尽管我建议以不同的方式将中间值存储在本地范围变量中。

完整的代码修复示例:

def parser():
    path = "file.txt"
    with open(path, 'r+') as file:
        msg = {}
        chat = []
        start = 0
        lines = file.readlines()
        for i in range(0, len(lines)):
            line = lines[i]

            if True:
                if line.startswith('x'):
                    msg['msg'] += line
                else:
                    msg['date'] = line[:8]
                    msg['msg'] = line[12:]
                    chat.append(msg)


        print(chat)

parser()

结果:

[{'date': '00.00.00', 'msg': 'Blabla\nx'}]

假设行if re.match('MY RULES', line) is not None: 文件中的所有行都是True

00.00.00 :  Blabla
x

【讨论】:

  • 我试过了,但还是不行。运行此代码,它将第一行附加到第一行。
  • 那么请检查 re.match() 规则,因为此代码适用于我的装备,我将在编辑中发布结果。
  • crazy...所以它肯定与规则有关,因为我的代码与您的代码相同,仅与规则有关。让我试试
  • 抱歉有一个小错误我重写了。请注意,为了简单起见,我将 re.match 改为 if True
  • 复制粘贴编辑后的示例,注意我更改了一些变量名。神奇的 line[8:] line[12:] 是符合你提供的输入文件的格式
【解决方案2】:

这个怎么样:

path = "file.txt"
with open (path, 'r') as f:
    msg = dict()
    for line in f.readlines():
        if line[0].isdigit():
            tmp = line.split(':')
            date = tmp[0].strip()
            msg[date] = ' '.join(*[x.split() for x in tmp[1:]])
        else:
            msg[date] += ' ' + ' '.join(*[line.split()])

我们逐行进行,如果该行的第一个字母是数字,我们假设它是一个日期并将其添加到我们的字典中 - 否则我们将找到的字符串添加到我们创建的最后一个字典条目中。 str.split() 确保您可以使用所有不同的空白字符。

您肯定可以用您的正则表达式替换 for 循环中的 if 语句...我在您的实现中看到的一般问题是,只要输入略有变化(例如,预期的更多空白字符),您的解决方案就会产生错误的结果。基本的python字符串操作真的很强大;)

更新

这应该会产生正确的输出:

*file.txt*
00.00.00 : Blabla
x
00.00.00 : Blabla2
x2


path = "file.txt"
with open (path, 'r') as f:
    lst = list()
    for line in f.readlines():
        if line[0].isdigit():
            tmp = line.split(':')
            date = tmp[0].strip()
            msg = {date: ' '.join(*[x.split() for x in tmp[1:]])}
            lst.append(msg)
        else:
            msg[date] += ' ' + ' '.join(*[line.split()])

print(lst)
>>> [{'00.00.00': 'Blabla x'}, {'00.00.00': 'Blabla2 x2'}]

我错过了您希望将每对分别存储在字典中并将其附加到列表中的部分。

【讨论】:

  • 嗯我可以试试,但你的第一次加入需要 2 个参数,对吗?加入只需要一个。
  • 不确定 2 个参数是什么意思。 str.join() 也适用于列表仅包含一个元素的情况,例如' '.join(*[x.split() for x in ['hello']])
  • 你是对的,它确实处理了一个元素列表。刚刚测试了你的建议,它可能有效!我会适应我的代码并更新它。
  • 没有按我的预期工作。一旦另一个 X 出现在其他行中,它就会跳过它们。例如:cat file.txt 00.00.00:Blabla x 00.00.00:Blabla2 x2 输出:{'00.00.00':'Blabla1'} {'00.00.00':'Blabla2'} {'00.00.00':' Blabla2 x2 '}
  • “00.00.00”代表什么?可以有不止一对具有相同的“00.00.00”吗?
猜你喜欢
  • 1970-01-01
  • 2016-10-14
  • 2018-12-01
  • 1970-01-01
  • 2013-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多