【问题标题】:Group .txt data into dataframe将 .txt 数据分组到数据框中
【发布时间】:2019-06-17 22:16:21
【问题描述】:

我有一个 .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。你确定你需要这么多组吗?我宁愿使用它们like here
  • 谢谢!但是我如何将它传递给熊猫数据框?我只想要“日期”、“时间”、“名称”、“消息”的四列。你有什么建议吗?
  • 使用带有str.extract的命名组,见regex101.com/r/K4ri2M/3
  • 终于成功了吗?

标签: python regex pandas


【解决方案1】:

这是我认为适用于我的情况的解决方案。问题是当它是 txt 数据时我使用的是 read_csv() 。在传入熊猫之前,我还需要使用正则表达式来构建我的格式:

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)

【讨论】:

    【解决方案2】:

    一个完整的解决方案看起来像

    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&lt;date&gt;\d+(?:\.\d+){2}) - 组“日期”:1 个以上数字,然后重复两次 . 和两个数字
    • ,\s - , 和一个空格
    • (?P&lt;time&gt;\d+(?::\d+){2}) - 组“时间”:1 个以上数字,然后重复两次 : 和两个数字
    • ]\s - ] 和一个空格
    • (?P&lt;name&gt;[^:]+) - 组“名称”:: 以外的一个或多个字符
    • : - 冒号
    • (?P&lt;message&gt;.*) - 组“消息”:任何 0+ 个字符,尽可能多,直到行尾。

    那么,逻辑如下:

    • 读入一行并针对该模式进行测试
    • 如果匹配,则初始化四个变量 - 日期、时间、名称和消息 - 详细信息
    • 如果下一行与模式不匹配,则将其视为消息的一部分,因此会附加到 message 变量中。

    【讨论】:

    • 感谢四位您的帮助,但当我这样做时:df = pd.read_csv('chat.txt', names = ['raw'])df = df['raw'].str.extract(r'(?s)\[(?P&lt;date&gt;\d+(?:\.\d+){2}),\s(?P&lt;time&gt;\d+(?::\d+){2})]\s(?P&lt;name&gt;[^:]+):(?P&lt;message&gt;.*?)(?=\[\d+\.\d+\.\d+,\s\d+:\d+:\d+]|\Z)', expand = True)print (df.tail)我收到&lt;bound method NDFrame.tail of date time name message[11.06.17 NaN NaN NaN NaN[11.06.17 NaN NaN NaN NaN[11.06.17 NaN NaN NaN NaN
    • @LGR 看起来像是读取文件的问题。我更新了解决方案。
    • 感谢您的回答。我找到了另一个解决方案,我将在下面发布:)
    猜你喜欢
    • 2020-12-14
    • 1970-01-01
    • 2014-10-18
    • 2015-05-20
    • 1970-01-01
    • 2022-12-14
    • 2020-06-13
    • 2018-04-19
    • 2020-09-14
    相关资源
    最近更新 更多