无用小程序之——论如何将导出为txt格式的QQ聊天记录进行合并

众所周知,QQ的PC端向我们提供了导出聊天记录的功能,并且允许我们导出为可读的文本文档(txt)格式,就像这样:

 然后导出之后就是这样的(不要怪我啥都看不见,这已经是我能提供的最多的信息了doge):

 结合上图以及生活常识我们可以发现,导出的聊天记录存在如下问题:

  1. 昵称、备注存在变动,而系统是不会自动更正这个变动的,如上图所示;
  2. 由于PC端聊天记录与移动端聊天记录是有限交换的,即只互相同步最近的聊天记录,这就导致PC端导出的记录存在大量的缺失;

对于上面所述问题2,想解决那是不可能的,但我们可以想办法缓解,比如将另一方关于此聊天的记录也导出来,合并为一个,于是这里又出现了新的问题:

  1. 两方昵称、备注不一样,得更新为统一的吧;
  2. 两边的聊天记录不能直接复制粘贴,得去重;

为了解决对应的问题,直接上代码(文中涉及的消息块样式在代码后面的图片):

import datetime
import re


with open('chat_history_1.txt', encoding='utf-8') as file_base:
    lines_base = file_base.readlines()
with open('chat_history_2.txt', encoding='utf-8') as file_add:
    lines_add = file_add.readlines()

pattern_ts = "%Y-%m-%d %H:%M:%S"
pattern_re = r"[0-9]{4}(-)[0-9]{2}(-)[0-9]{2}( )[0-9]{1,2}(:)[0-9]{2}(:)[0-9]{2}"
pattern_re_2 = \
    r"[0-9]{4}(-)[0-9]{2}(-)[0-9]{2}( )[0-9]{1,2}(:)[0-9]{2}(:)[0-9]{2}( )(备注1|备注2|备注3)"  # 这个地方备注或昵称就是聊天记录里面显示的其中一方的昵称(包括两个聊天记录里面所有涉及到的其中一方的昵称或备注)
pattern_re_3 = r"[0-9]{4}(-)[0-9]{2}(-)[0-9]{2}( )[0-9]{1,2}(:)[0-9]{2}(:)[0-9]{2}( )(备注1|备注2|备注3)"  # 这个地方备注或昵称就是聊天记录里面显示的另一方的昵称(包括两个聊天记录里面所有涉及到的另一方的昵称或备注)


list_stamp = []
for line_base in lines_base:
    result = re.match(pattern_re, line_base)  # 这里是读取chat_history_1的消息发送的时间轴(为了下一步合并去重做准备)
    if result:
        result = result.group()
        timestamp = datetime.datetime.strptime(result, pattern_ts).timestamp()  # 转换为时间戳
        list_stamp.append(timestamp)  # 添加入时间轴列表
    else:
        list_stamp.append(0.0)  # 这个我也不知道是啥了,反正有用,不知道有啥用,估计就是占位?我也不确定,自己看着办吧

for index_add in range(len(lines_add)):  #外层逐行循环chat_history_2里面的信息(索引)
    print(index_add)  # 看看循环到哪一个了
    result = re.match(pattern_re, lines_add[index_add])  # 还是格式化时间
    sign = 0  # 标签,用于标记这个是否是一个重复的信息(从而确定是否要转移该条消息)
    if result:  # 如果该行有格式化时间,就肯定是(极大概率是,毕竟应该不会有人给别人发消息的时候发格式化时间吧)一个消息的开头
        sign = 1
        result = result.group()
        timestamp = datetime.datetime.strptime(result, pattern_ts).timestamp()  # 转时间戳
        for index_base in range(len(list_stamp)):  # 开始对比时间轴进行插值
            if timestamp < list_stamp[index_base]:
                sign = 2
                counter = 0
                index_current = index_add
                while True:  # 检查这部分消息块(信息块结构见下图)总共占用了几行
                    index_current += 1
                    try:
                        if not re.match(pattern_re, lines_add[index_current]):
                            counter += 1
                        else:
                            break
                    except IndexError:
                        break
                list_stamp.insert(index_base, timestamp)
                lines_base.insert(index_base, lines_add[index_add])  # 插入首行信息,即包含格式化时间等的那一行,同步更新时间戳和内容
                index_base += 1
                index_add += 1
                for i in range(counter):  # 插入本信息块(信息块结构见下图)中的其余信息
                    list_stamp.insert(index_base, 0)
                    lines_base.insert(index_base, lines_add[index_add])
                    index_base += 1
                    index_add += 1
                break
            elif timestamp == list_stamp[index_base]:  # 如果出现时间戳对上了,那就说明消息重复了,不需要合并过来
                sign = 2
                break
            else:
                continue
    if sign == 1:  # 为1代表时间戳直接干到底了,也就是时间戳超出了时间轴的范围,到达了最末端,说明chat_history_2里有比chat_history_1里最后一条记录还要晚的记录,这时候就不用插值了,一个个往里写就行了,下面的追加操作就和之前的插值理论上没啥区别,只不过变成了append
        counter = 0
        index_current = index_add
        while True:
            index_current += 1
            print(index_current)
            try:
                if not re.match(pattern_re, lines_add[index_current]):
                    counter += 1
                else:
                    break
            except IndexError:
                break
        lines_base.append(lines_add[index_add])
        index_add += 1
        for i in range(counter):
            lines_base.append(lines_add[index_add])
            index_add += 1

for index in range(len(lines_base)):  # 这个是在所有信息都合并完之后,重新统一所有乱七八糟的昵称和内容
    result1 = re.match(pattern_re_2, lines_base[index])
    result2 = re.match(pattern_re_3, lines_base[index])
    if result1:
        result1 = result1.group()
        result1 = re.match(pattern_re, result1).group()
        result1 += " 统一后一方的昵称1\n"  # 和前面的正则表达式对起来哈,对错了就悲剧了
        lines_base[index] = result1
    elif result2:
        result2 = result2.group()
        result2 = re.match(pattern_re, result2).group()
        result2 += " 统一后另一方的昵称\n"
        lines_base[index] = result2
    else:
        continue

 
with open('chat_history_merged', 'w+', encoding='utf-8') as final:  # 写入最终文件
    final.writelines(lines_base)

(上图为消息块格式,注意,最后的那个换行是不能删掉的)

除此之外,对于文件格式的要求:

文件开头类似:

文件结尾类似:

 

就总之,整个文件就只剩下消息块,全都是消息块,从头到尾全部是完整的消息块(务必都得是完整的,导出来的结果一般都是完整的,把头部去掉就行,头部类似下图)

 哦等等,最后,关于我为什么要整这么个程序……

 就是方便查看,然后又有点强迫症,然后正好考完试了……

四舍五入就是闲的。

不知给这个程序取个什么名字好呢?

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河之书Liu_Zixin

不要打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值