Python 如何使用前导空格将txt文件转换为json?

Python 如何使用前导空格将txt文件转换为json?,python,json,Python,Json,我已格式化txt文件,如下所示: Hostinfo开始 日期1908191522 主持人迈达斯 域测试 硬件单元平台x86硬件单元64 服务器类型虚拟 中央处理器信息 CPU_型英特尔(R)至强(R)CPU E7-8867 v4@2.40GHz CPU_计数2 堆芯计数2 线程计数8 内存32951312 kB 操作系统启动 操作系统Linux OS_版本4.9.0-6-amd64 操作系统正常运行时间536天21:08 操作系统端 发布Debian GNU/Linux 9(扩展版) 第9版发布

我已格式化txt文件,如下所示:

Hostinfo开始
日期1908191522
主持人迈达斯
域测试
硬件单元平台x86硬件单元64
服务器类型虚拟
中央处理器信息
CPU_型英特尔(R)至强(R)CPU E7-8867 v4@2.40GHz
CPU_计数2
堆芯计数2
线程计数8
内存32951312 kB
操作系统启动
操作系统Linux
OS_版本4.9.0-6-amd64
操作系统正常运行时间536天21:08
操作系统端
发布Debian GNU/Linux 9(扩展版)
第9版发布
发布补丁级别
主机信息端
使用前导空格数需要将其转换为json格式,如下所示:

"Hostinfo": [
{
  "DATE": "190819 1522"
  "HOST": "midas"
  "DOMAIN": "test.de"
  "HW_PLATFORM": "x86_64"
  "SERVER_TYPE": "virtual"
  "CPU_INFO": {
    "CPU_TYPE": "Intel(R) Xeon(R) CPU E7-8867 v4 @ 2.40GHz"
    "CPU_COUNT": "2"
    "CORE_COUNT": "2"
    }
  "THREAD_COUNT": "8"
  "MEMORY": "32951312 kB"
  "OS": [
      {
      "OS": "Linux"
      "OS_VERSION": "4.9.0-6-amd64"
      "OS_UPTIME": "536 days 21:08"
      }
    ]
  "RELEASE": "Debian GNU/Linux 9 (stretch)"
  "RELEASE_VERSION": "9"
  "RELEASE_PATCHLEVEL" : ""
}
]
我对此脚本有一些承诺,但无法解决如何将花括号之间的行设置为上字典(级别)的对象的问题:

#/usr/bin/python
导入json
进口itertools
导入字符串
进口稀土
文件名='commands.txt'
命令={}
打开(文件名)为fh时:
上一行=0
mark_line=“”
对于fh中的线路:
当前行=((len(line)-len(line.lstrip())/2)
差异=当前\u线-上一\u线
如果重新搜索('Start$',line.strip()):
line=line.strip().replace('Start',':{'))
打印(行)
mark_line=“start_line”
elif重新搜索('Ende$',line.strip()):
line=line.strip().replace('Ende','')
打印(“}”)
mark_line=“end_line”
elif diff==0:
打印(line.strip())S
elif差异>0:
如果标记线==“开始线”或标记线==“结束线”:
mark_line=“0”
其他:
打印(“{”)
打印(line.strip())
elif差异<0:
如果标记线==“开始线”或标记线==“结束线”:
mark_line=“0”
其他:
打印(“}”)
打印(line.strip())
上一行=((len(line)-len(line.lstrip())/2)
#line=(str((len(line)-len(line.lstrip())/2)+“;”+line.strip())
尝试:
命令,描述=line.strip().split(“”,1)
commands[command]=description.strip()
除例外情况外:
command=line.strip()
description=“”
commands[command]=description.strip()
打印(json.dumps(命令,缩进=2,排序键=True))
也许你能给我一些解决这个问题的方法或者建议?可能是某个模块简化了这个脚本


UPD:在我的mess脚本中添加一些json标记。如果我走错了/走对了,你能得到建议吗

您可以将
itertools.groupby
与递归一起使用:

import itertools as it, re
data = [[*re.findall('^\s+', b), *re.split('(?<=[A-Z])\s+', i)] for b in open('os_stuff.txt') if not (i:=re.sub('^\s+|\sStart\n$', '', b)).endswith('End\n')]
def to_tree(d):
   _d = [(a, list(b)) for a, b in it.groupby(d, key=lambda x:bool(re.findall('^\s+$', x[0])))]
   new_dict, _last = {}, None
   for i, [a, b] in enumerate(_d):
      if not a:
         for j, *k in b:
            if not k or (not k[0] and i < len(_d) - 2):
               _last = j
            else:
               new_dict[j] = ' '.join(k).strip('\n')
      else:
         new_dict[_last] = [to_tree([[k[2:], *j] if k[2:] else j for k, *j in b])]
   return new_dict
输出:

{
  "Hostinfo": [
    {
        "DATE": "190819 1522",
        "HOST": "midas",
        "DOMAIN": "test.de",
        "HW_PLATFORM": "x86_64",
        "SERVER_TYPE": "virtual",
        "CPU_INFO": [
            {
                "CPU_TYPE": "Intel(R) Xeon(R) CPU E7-8867 v4 @ 2.40GHz",
                "CPU_COUNT": "2",
                "CORE_COUNT": "2"
            }
        ],
        "THREAD_COUNT": "8",
        "MEMORY": "32951312 kB ",
        "OS": [
            {
                "OS": "Linux",
                "OS_VERSION": "4.9.0-6-amd64",
                "OS_UPTIME": "536 days 21:08"
            }
        ],
        "RELEASE": "Debian GNU/Linux 9 (stretch)",
        "RELEASE_VERSION": "9",
        "RELEASE_PATCHLEVEL": ""
     }
  ]
}
编辑:Python2.7解决方案:

import itertools as it, re
new_data = [[i, re.sub('^\s+|\sStart\n$', '', i)] for i in open('os_stuff.txt')]
data = [re.findall('^\s+', a)+re.split('(?<=[A-Z])\s+', b) for a, b in new_data if not b.endswith('End\n')]
def to_tree(d):
  _d = [(a, list(b)) for a, b in it.groupby(d, key=lambda x:bool(re.findall('^\s+$', x[0])))]
  new_dict, _last = {}, None
  for i, [a, b] in enumerate(_d):
     if not a:
       for j_k in b:
         if not j_k[1:] or (not j_k[1:][0] and i < len(_d) - 2):
            _last = j_k[0]
         else:
            new_dict[j_k[0]] = ' '.join(j_k[1:]).strip('\n')
     else:
       new_dict[_last] = [to_tree([[k_j[0][2:]]+k_j[1:] if k_j[0][2:] else k_j[1:] for k_j in b])]
  return new_dict


print(to_dict(data))
按原样导入itertools,重新
新的_数据=[[i,re.sub('^\s+|\sStart\n$',''''i],i)]用于打开的i('os_stuff.txt')]

data=[re.findall('^\s+',a)+re.split('(?您的输入文件看起来几乎像有效的YAML(q.v.),但它有点不正确。您应该返回数据源,尝试直接获取有效的格式,例如YAML、JSON、XML等。看起来
OS
Start
标记,但
CPU INFO
没有。对吗?从语法上讲,这种格式很混乱。似乎有显式关键字
Start
End
用于
Hostinfo
OS
中使用的块边界,但同样不用于
CPU INFO
,其中块由缩进指示。这是否应被视为相等?如何将json转换回此格式,具有两个完全相同的格式选项?;)为什么
CPU INFO
没有下划线,并且没有变成
CPU
,而
OS Start
变成
OS
?好的,谢谢大家的关注,让我们假设开始、结束块是json数组,没有开始和结束块的缩进是json字典。PS:更新输出,抱歉搞砸了。还有CPU\INFO将有下划线,这是我的错误。如果出现其他问题,我无法对输入产生任何影响。抱歉,我正在尝试运行您的脚本,但python输出语法错误:(在数据变量lineIf中,如果我理解正确,则此脚本仅适用于python 3。8@Kein这是正确的,它使用了赋值表达式。我会将解决方案更新为print(json.dumps(到_树(数据),缩进=4))
{
  "Hostinfo": [
    {
        "DATE": "190819 1522",
        "HOST": "midas",
        "DOMAIN": "test.de",
        "HW_PLATFORM": "x86_64",
        "SERVER_TYPE": "virtual",
        "CPU_INFO": [
            {
                "CPU_TYPE": "Intel(R) Xeon(R) CPU E7-8867 v4 @ 2.40GHz",
                "CPU_COUNT": "2",
                "CORE_COUNT": "2"
            }
        ],
        "THREAD_COUNT": "8",
        "MEMORY": "32951312 kB ",
        "OS": [
            {
                "OS": "Linux",
                "OS_VERSION": "4.9.0-6-amd64",
                "OS_UPTIME": "536 days 21:08"
            }
        ],
        "RELEASE": "Debian GNU/Linux 9 (stretch)",
        "RELEASE_VERSION": "9",
        "RELEASE_PATCHLEVEL": ""
     }
  ]
}
import itertools as it, re
new_data = [[i, re.sub('^\s+|\sStart\n$', '', i)] for i in open('os_stuff.txt')]
data = [re.findall('^\s+', a)+re.split('(?<=[A-Z])\s+', b) for a, b in new_data if not b.endswith('End\n')]
def to_tree(d):
  _d = [(a, list(b)) for a, b in it.groupby(d, key=lambda x:bool(re.findall('^\s+$', x[0])))]
  new_dict, _last = {}, None
  for i, [a, b] in enumerate(_d):
     if not a:
       for j_k in b:
         if not j_k[1:] or (not j_k[1:][0] and i < len(_d) - 2):
            _last = j_k[0]
         else:
            new_dict[j_k[0]] = ' '.join(j_k[1:]).strip('\n')
     else:
       new_dict[_last] = [to_tree([[k_j[0][2:]]+k_j[1:] if k_j[0][2:] else k_j[1:] for k_j in b])]
  return new_dict


print(to_dict(data))