【问题标题】:Make dictionary from txt file using re使用 re 从 txt 文件制作字典
【发布时间】:2020-09-25 22:35:48
【问题描述】:

考虑 assets/logdata.txt 中的标准网络日志文件。该文件记录了用户在访问网页时所做的访问(就像这个!)。日志的每一行都有以下几项:

  • 主机(例如,'146.204.224.152'
  • 用户名(例如,'feest6811' 注意:有时用户名会丢失!在这种情况下,请使用“-”作为用户名的值。)
  • 发出请求的时间(例如,'21/Jun/2019:15:45:24 -0700'
  • post 请求类型(例如,'POST /incentivize HTTP/1.1' 注意:并非所有内容都是 POST!)

您的任务是将其转换为字典列表,其中每个字典如下所示:

example_dict = {"host":"146.204.224.152", 
                "user_name":"feest6811", 
                "time":"21/Jun/2019:15:45:24 -0700",
                "request":"POST /incentivize HTTP/1.1"}

这是txt数据文件的样本。

我写了这几行代码:

import re
def logs():
    with open("assets/logdata.txt", "r") as file:
        logdata = file.read()
        #print(logdata)
        pattern="""
        (?P<host>.*)        
        (-\s)   
        (?P<user_name>\w*)  
        (\s) 
        ([POST]*)
        (?P<time>\w*)               
                 """
        for item in re.finditer(pattern,logdata,re.VERBOSE):
            print(item.groupdict())
        return(item)
logs()

它帮助我完成了"host""user_name",但是我无法继续完成其余的要求。有人可以帮忙吗?

【问题讨论】:

    标签: python regex


    【解决方案1】:

    我的朋友试试这个

    import re
    
    
    def logs():
        logs = []
        w = '(?P<host>(?:\d+\.){3}\d+)\s+(?:\S+)\s+(?P<user_name>\S+)\s+\[(?P<time>[-+\w\s:/]+)\]\s+"(?P<request>.+?.+?)"'
        with open("assets/logdata.txt", "r") as f:
            logdata = f.read()
        for m in re.finditer(w, logdata):
            logs.append(m.groupdict())
        return logs
    

    【讨论】:

    【解决方案2】:

    您使用\w 来获取user_names,但是\w 不包括可以在日志中的- (Common Log Format (CLF)),因此您可以使用\S+ (一个或多个除空格之外的任何内容)。对于time,您可以创建一个捕获组,仅允许该字段的预期字符(类)(例如\w\s-+ 用于时区、/ 用于日期和: 用于时间)包围通过方括号(文字),可以使用"request 进行类似的捕获。

    import re
    
    regex = re.compile(
        r'(?P<host>(?:\d+\.){3}\d+)\s+'
        r'(?:\S+)\s+'
        r'(?P<user_name>\S+)\s+'
        r'\[(?P<time>[-+\w\s:/]+)\]\s+'
        r'"(?P<request>POST.+?)"'
    )
    
    def logs():
        data = []
        with open("sample.txt", "r") as f:
            logdata = f.read()
        for m in regex.finditer(logdata):
            data.append(m.groupdict())
        return data
    
    print(logs())
    

    (将第一行的用户名替换为“-”以在第二行进行测试)

    [
       {
          "host":"146.204.224.152",
          "user_name":"feest6811",
          "time":"21/Jun/2019:15:45:24 -0700",
          "request":"POST /incentivize HTTP/l.l"
       },
       {
          "host":"146.204.224.152",
          "user_name":"-",
          "time":"21/Jun/2019:15:45:24 -0700",
          "request":"POST /incentivize HTTP/l.l"
       },
       {
          "host":"144.23.247.108",
          "user_name":"auer7552",
          "time":"21/Jun/2019:15:45:35 -0700",
          "request":"POST /extensible/infrastructures/one-to-one/enterprise HTTP/l.l"
       },
        ...
    

    【讨论】:

    • 很好用,但是如果我想指定请求只打印请求:“POST”,我该怎么办?
    • @ahmed-sharshar 您必须将POST 添加到最后一个捕获组。我编辑了答案。
    • 看起来是对的,但是使用这个断言发生了一些错误:``` assert len(logs()) == 979 one_item={'host': '146.204.224.152', 'user_name' : 'feest6811', 'time': '21/Jun/2019:15:45:24 -0700', 'request': 'POST /incentivize HTTP/1.1'} assert one_item in logs(), "对不起,这个项目应该在日志结果中,检查你的格式" ```
    • @ahmed-sharshar 我在Common Log Format (CLF) 描述之后编辑了问题,看看现在是否有效。
    【解决方案3】:

    请看下面的代码:

    import re
    
    regex = re.compile(
        r'(?P<host>(?:\d+\.){1,3}\d+)\s+-\s+'
        r'(?P<user_name>[\w+\-]+)?\s+'
        r'\[(?P<time>[-\w\s:/]+)\]\s+'
        r'"(?P<request>\w+.+?)"'
    )
    
    def logs():
        data = []
        with open("assets/logdata.txt", "r") as f:
            logdata = f.read()
            for item in regex.finditer(logdata):
                x = item.groupdict()
                if x["user_name"] is None:
                    x["user_name"] = "-"
                data.append(x)
        return data
    
    logs()
    

    请在下面找到输出部分:

    [{'主机': '146.204.224.152', 'user_name': 'feest6811', '时间': '21/Jun/2019:15:45:24 -0700', 'request': 'POST /incentivize HTTP/1.1'}, {'主机':'197.109.77.178', 'user_name': 'kertzmann3129', '时间': '21/Jun/2019:15:45:25 -0700', '请求':'删除 /virtual/solutions/target/web+services HTTP/2.0'}, {'主机':'156.127.178.177', '用户名':'okuneva5222', '时间': '21/Jun/2019:15:45:27 -0700', 'request': 'DELETE /interactive/transparent/nices/revolutionize HTTP/1.1'}, {'主机':'100.32.205.59', 'user_name': 'ortiz8891', '时间': '21/Jun/2019:15:45:28 -0700', “请求”:“补丁 /architectures HTTP/1.0”}, {'主机':'168.95.156.240', 'user_name': 'stark2413', '时间': '21/Jun/2019:15:45:31 -0700', 'request': 'GET /engage HTTP/2.0'}, .....] 文本文件的每一行包含 979 个字典。

    谢谢

    【讨论】:

      【解决方案4】:
      import re
      def logs():
      mydata = []
      with open("assets/logdata.txt", "r") as file:
      logdata = file.read()
      pattern="""
      (?P<host>.*)
      (\s+)
      (?:\S+)
      (\s+)
      (?P<user_name>\S+)
      (\s+)
      \[(?P<time>.*)\]\
      (\s)
      (?P<request>"(.)*")"""
      for item in re.finditer(pattern,logdata,re.VERBOSE):
      new_item = (item.groupdict())
      mydata.append(new_item)
      return(mydata)
      

      【讨论】:

      • 欢迎来到 Stack Overflow。没有任何解释的代码转储很少有帮助。 Stack Overflow 是关于学习的,而不是提供 sn-ps 来盲目复制和粘贴。请edit您的问题并解释它如何比OP提供的更好。此外,缩进在 Python 中很重要,此代码将生成 IndentationError。见How to Answer
      【解决方案5】:
          import re
          def logs():
              with open("assets/logdata.txt", "r") as file:
                  logdata = file.read()
      
          result = []
          pattern = re.compile(
          r'(?P<host>.*)\s'
          r'(?:-)\s'
          r'(?P<user_name>.*)\s'
          r'\[(?P<time>.*)\]\s'
          r'"(?P<request>.*)"')
          for m in pattern.finditer(logdata):
              data = (m.groupdict())
              result.append(data)
          return result
      

      【讨论】:

      • 您能否在您的代码中添加一些解释来描述它为什么/如何工作?
      • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
      【解决方案6】:
      import re
      def logs():
          dict=[]
          with open("assets/logdata.txt", "r") as file:
              logdata = file.read()
              pattern="""(?P<host>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)
                          (\ - \ )
                          (?P<user_name>(\w*)(\S))
                          (\  \S)
                          (?P<time>\d+\S\w*\S\d+\S\d+\S\d+\S\d+\s\S\d+)
                          (\S\s\S)
                          (?P<request>\w*\s\S*\s\w*\S\d.\d*)
                       """
          
          for item in re.finditer(pattern,logdata,re.VERBOSE): 
              dict.append(item.groupdict())
          return dict 
          raise NotImplementedError()
      

      #1 import re 模块使用正则表达式

      #2 定义函数

      #3 打开需要的文件

      #4 读取文件

      #5 写下所需字符串的模式。 有关正则表达式的更多详细信息,请阅读文档。 https://docs.python.org/3/library/re.html#module-re

      【讨论】:

      • 欢迎来到 Stack Overflow。没有任何解释的代码转储很少有帮助。 Stack Overflow 是关于学习的,而不是提供 sn-ps 来盲目复制和粘贴。请编辑您的问题并解释它如何比 OP 提供的更好。见How to Answer
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-12
      • 2021-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多