【问题标题】:From text doc to JSON with python使用 python 从文本文档到 JSON
【发布时间】:2022-11-10 02:19:48
【问题描述】:

假设我有多个看起来像这样的 txt 文件(缩进为 4 个空格):

key1=value1
key2
    key2_1=value2_1
    key2_2
        key2_2_1=value2_2_1
    key2_3=value2_3
key3=value3

如何将其中一个(或全部)转换为这种格式:

{
'key1':'value1',
'key2':
    {
    'key2_1':'value2_1',
    'key2_2':
        {
        'key2_2_1':'value2_2_1'
        },
    'key2_3':'value2_3'
    },
'key3':'value3'
}

或以扁平的字典格式。

我感谢任何cmets。最好的,

奈杰尔

######################################### 新纳入(截至 2022 年 10 月 28 日):

我正在使用@jrynes 提出的代码,但稍作改动:我使用pathlib 调用目录中的文件,然后pathlib 中的.splitlines() 方法将拆分行:

import json

def convertIndentation(inputString):
    indentCount = 0
    indentVal = "    "
    for position, eachLine in enumerate(inputString):
        if "=" not in eachLine:
            continue
        else:
            strSplit = eachLine.split("=", 1)
            prevIndent = inputString[position].count(indentVal)
            newVal = (indentVal * (prevIndent + 1)) + strSplit[1]
            inputString[position] = strSplit[0] + '\n'
            inputString.insert(position+1, newVal)
    flatList = "".join(inputString)
    return flatList

class Node:
    def __init__(self, indented_line):
        self.children = []
        self.level = len(indented_line) - len(indented_line.lstrip())
        self.text = indented_line.strip()

    def add_children(self, nodes):
        childlevel = nodes[0].level

        while nodes:
            node = nodes.pop(0)
            if node.level == childlevel:
                self.children.append(node)
            elif node.level > childlevel:
                nodes.insert(0,node)
                self.children[-1].add_children(nodes)
            elif node.level <= self.level:
                nodes.insert(0,node)
                return

    def as_dict(self):
        if len(self.children) > 1:
            return {self.text: [node.as_dict() for node in self.children]}
        elif len(self.children) == 1:
            return {self.text: self.children[0].as_dict()}
        else:
            return self.text

接着:

from pathlib import Path
def txt_to_json(filename: Path):
    content = filename.read_text(encoding='utf-8').splitlines()
    fileParse = convertIndentation(content)
    root = Node('root')
    root.add_children([Node(line) for line in fileParse.splitlines() if line.strip()])
    d = root.as_dict()['root']
    jsonOutput = json.dumps(d, indent = 4, sort_keys = False)
    print(jsonOutput)

def main():
    search_directory = Path.home().joinpath('OneDrive', 'Documents', 'LAB', 'lean')
    for txt_file in search_directory.glob("**/*.txt"):
        txt_to_json(txt_file)

if __name__ == '__main__':
    main()

在实现上述代码后打开文件时,我得到以下信息:

观察到 python 无法找出行尾(没有'\n')。但是,当我使用@jrynes 提出的方法.readlines() 时,我得到了这个:

使用@jrynes 的 Python 方法观察,在每行的末尾看到 '\n'。

当我使用pathlib 时,这里是“jsonOutput”:

我的问题是:我使用pathlib 的方法有什么问题?为什么它不能找出行尾?

【问题讨论】:

  • 你尝试了什么?
  • 嗨@Atif,JSON 是一种高效的数据交换格式。我们可以使用它将数据加载到数据库中,最终我们可以在数据库中对其进行转换并运行数据分析。

标签: python json dictionary automation txt


【解决方案1】:

您可以尝试以下方法:

# helper method to convert equals sign to indentation for easier parsing
def convertIndentation(inputString):
    indentCount = 0
    indentVal = "    "
    for position, eachLine in enumerate(inputString):
        if "=" not in eachLine:
            continue
        else:
            strSplit = eachLine.split("=", 1)
            #get previous indentation
            prevIndent = inputString[position].count(indentVal)
            newVal = (indentVal * (prevIndent + 1)) + strSplit[1]
            inputString[position] = strSplit[0] + '
'
            inputString.insert(position+1, newVal)
    flatList = "".join(inputString)
    return flatList

# helper class for node usage
class Node:
    def __init__(self, indented_line):
        self.children = []
        self.level = len(indented_line) - len(indented_line.lstrip())
        self.text = indented_line.strip()

    def add_children(self, nodes):
        childlevel = nodes[0].level

        while nodes:
            node = nodes.pop(0)
            if node.level == childlevel: # add node as a child
                self.children.append(node)
            elif node.level > childlevel: # add nodes as grandchildren of the last child
                nodes.insert(0,node)
                self.children[-1].add_children(nodes)
            elif node.level <= self.level: # this node is a sibling, no more children
                nodes.insert(0,node)
                return

    def as_dict(self):
        if len(self.children) > 1:
            return {self.text: [node.as_dict() for node in self.children]}
        elif len(self.children) == 1:
            return {self.text: self.children[0].as_dict()}
        else:
            return self.text

# process our file here
with open(filename, 'r') as fh:
    fileContent = fh.readlines()
    fileParse = convertIndentation(fileContent)
    # convert equals signs to indentation
    root = Node('root')
    root.add_children([Node(line) for line in fileParse.splitlines() if line.strip()])
    d = root.as_dict()['root']
    # this variable is storing the json output
    jsonOutput = json.dumps(d, indent = 4, sort_keys = False)
    print(jsonOutput)

这应该会产生一些输出,如下所示:

[
    {
        "key1": "value1"
    },
    {
        "key2": [
            {
                "key2_1": "value2_1"
            },
            {
                "key2_2": {
                    "key2_2_1": "value2_2_1"
                }
            },
            {
                "key2_3": "value2_3"
            }
        ]
    },
    {
        "key3": "value3"
    }
]

【讨论】:

  • 谢谢@jrynes。这个解决方案非常准确。做得好。
  • 嗨@jrynes,我意识到当我使用pathlib 处理多个文件和拆分行时,脚本无法找出新行,并且您提出的代码与pathlib 中断。我将编辑主要问题以更好地澄清这一点。
猜你喜欢
  • 2017-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多