将 .txt 数据分组成数据框。

3

我有一个包含如下数据的 .txt 文件:

[12.06.17, 13:18:36] Name1: Test test test
[12.06.17, 13:20:20] Name2 ❤️: blabla
[12.06.17, 13:20:44] Name2 ❤️: words words words
words
words
words
[12.06.17, 13:29:03] Name1: more words more words
[12.06.17, 13:38:52] Name3 Surname Nickname: 
[12.06.17, 13:40:37] Name1: message?

请注意,消息前可能会有多个名称,并且可以出现多行消息。我已经尝试了许多方法来将数据分成“日期”,“时间”,“名称”和“消息”组。 我已经能够找到这个正则表达式。
(.)(\d+\.\d+\.\d+)(,)(\s)(\d+:\d+:\d+)(.)(\s)([^:]+)(:)

能够捕获到消息之前的所有内容(参见:https://regex101.com/r/hQlgeM/3)。但我无法弄清如何添加消息,以便将多行消息分组到上一条消息中。

最后:如果我能够使用正则表达式从.txt文件中捕获每个组,那么我该如何将每个组传递到单独的列中。我已经查看了三天的示例,但仍然无法弄清如何最终构建此数据帧。

我尝试使用的代码:

df = pd.read_csv('chat.txt', names = ['raw'])

data = df.iloc[:,0]

re.match(r'\[([^]]+)\] ([^:]+):(.*)', data)

另一种尝试失败了:

input_file = open("chat.txt", "r", encoding='utf-8')

content = input_file.read()

df = pd.DataFrame(content, columns = ['raw'])

df['date'] = df['raw'].str.extract(r'^(.)(\d+\.\d+\.\d+)', expand=True)

df['time'] = df['raw'].str.extract(r'(\s)(\d+:\d+:\d+)', expand=True)

df['name'] = df['raw'].str.extract(r'(\s)([^:]+)(:)', expand=True)

df['message'] = df['raw'].str.extract(r'^(.)(?<=:).*$', expand=True)

df

你可以使用 (?s)(\[)(\d+\.\d+\.\d+)(,)(\s)(\d+:\d+:\d+)(])(\s)([^:]+)(:)(.*?)(?=\[\d+\.\d+\.\d+,\s\d+:\d+:\d+]|\Z),参见demo。你确定需要这么多组吗?我宁愿像这里那样使用它们。 - Wiktor Stribiżew
谢谢!但是我如何将此传入pandas数据框架?我只想要四列,分别为“日期”、“时间”、“姓名”和“消息”。你有什么建议吗? - LGR
使用 str.extract 和命名组,参见 https://regex101.com/r/K4ri2M/3 - Wiktor Stribiżew
最终成功了吗? - Wiktor Stribiżew
2个回答

3
一个完整的解决方案应该如下所示:
import pandas as pd
import io, re

file_path = 'chat.txt'
rx = re.compile(r'\[(?P<date>\d+(?:\.\d+){2}),\s(?P<time>\d+(?::\d+){2})]\s(?P<name>[^:]+):(?P<message>.*)')
col_list = []
date = time = name = message = ''

with io.open(file_path, "r", encoding = "utf-8", newline="\n") as sr:
    for line in sr:
        m = rx.match(line)
        if m:
            col_list.append([date, time, name, message])
            date = m.group("date")
            time = m.group("time")
            name = m.group("name")
            message = m.group("message")
        else:
            if line:
                message += line

df = pd.DataFrame(col_list, columns=['date', 'time', 'name', 'message'])

模式细节

  • \[ - 匹配一个 [ 字符
  • (?P<date>\d+(?:\.\d+){2}) - 分组 "date":匹配 1 个或多个数字,后跟两次重复的 . 和两个数字
  • ,\s - 匹配 , 和一个空格
  • (?P<time>\d+(?::\d+){2}) - 分组 "time":匹配 1 个或多个数字,后跟两次重复的 : 和两个数字
  • ]\s - 匹配 ] 和一个空格
  • (?P<name>[^:]+) - 分组 "name":匹配一个或多个字符(不包括 :
  • : - 冒号
  • (?P<message>.*) - 分组 "message":任意数量的字符,尽可能多地匹配,直到行末。

然后,逻辑如下:

  • 读取一行并对其进行模式匹配
  • 如果匹配成功,则初始化四个变量 - date、time、name 和 message - 细节
  • 如果下一行不匹配模式,则被视为消息的一部分,因此将其附加到 message 变量中。

谢谢你的帮助,但当我执行以下代码时: df = df['raw'].str.extract(r'(?s)\[(?P\d+(?:\.\d+){2}),\s(?P - LGR
@LGR 看起来是读取文件的问题。我已经更新了解决方案。 - Wiktor Stribiżew
谢谢你的回答。我找到了另一个解决方案,我会在下面发布 :) - LGR

0

这是我在我的情况下找到的解决方案。问题在于我使用了read_csv(),而数据实际上是txt格式的。此外,在将其传递给pandas之前,我需要使用正则表达式来构建我的格式:

import re
import pandas as pd

chat = open('chat.txt').read()
pattern = r'(?s)\[(?P<date>\d+(?:\.\d+){2}),\s(?P<time>\d+(?::\d+){2})]\s(?P<name>[^:]+):(?P<message>.*?)(?=\[\d+\.\d+\.\d+,\s\d+:\d+:\d+]|\Z)'

for row in re.findall(pattern, chat):
    row

df = pd.DataFrame(re.findall(pattern, chat), columns=['date', 'time', 'name', 'message'])

print (df.tail)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接