Heim >Backend-Entwicklung >Golang >Konvertieren Sie durch Punkte getrennte Werte mit Python in eine Go-Struktur

Konvertieren Sie durch Punkte getrennte Werte mit Python in eine Go-Struktur

王林
王林nach vorne
2024-02-10 13:33:08998Durchsuche

使用 Python 将点分隔值转换为 Go 结构

php-Editor Youzi stellt in diesem Artikel vor, wie man mit Python durch Punkte getrennte Werte (wie „key1.subkey1.subkey2“) in eine Struktur in der Go-Sprache umwandelt. Dieser Transformationsprozess ist nützlich zum Extrahieren und Verarbeiten von Daten aus Konfigurationsdateien oder API-Antworten. Wir werden die rekursiven Funktionen und Go-Sprachstrukturen von Python verwenden, um diese Konvertierung zu implementieren, und detaillierte Codebeispiele und Erklärungen geben. Nach dem Studium dieses Artikels werden die Leser in der Lage sein, punktgetrennte Werte problemlos zu verarbeiten und umzuwandeln, wodurch die Effizienz und Flexibilität der Datenverarbeitung verbessert wird.

Frageninhalt

Dies ist eine spezifische Anforderung für eine Anwendung, die die Konfiguration ändern kann (insbesondere den WSO2-Identitätsserver, da ich Go verwende, um den Kubernetes-Operator dafür zu schreiben). Aber das ist hier wirklich nicht relevant. Ich möchte eine Lösung erstellen, die eine einfache Verwaltung einer großen Anzahl von Konfigurationskarten ermöglicht, um Go-Strukturen zu generieren. Diese Konfigurationen werden in .csv

abgebildet

Link zu .csv – my_configs.csv

Ich möchte, Schreiben Sie ein Python-Skript, das automatisch Go-Strukturen generiert, damit alle Änderungen an der Anwendungskonfiguration aktualisiert werden können, indem Sie einfach das Python-Skript ausführen, um die entsprechende Go-Struktur zu erstellen. Ich beziehe mich auf die Konfiguration der Anwendung selbst. Beispielsweise können ToML-Schlüsselnamen in CSV geändert/neue Werte hinzugefügt werden.

Bisher habe ich erfolgreich ein Python-Skript erstellt, das mein Ziel fast erreicht. Das Drehbuch lautet:

import pandas as pd

def convert_to_dict(data):
    result = {}
    for row in data:
        current_dict = result
        for item in row[:-1]:
            if item is not none:
                if item not in current_dict:
                    current_dict[item] = {}
                current_dict = current_dict[item]
    return result

def extract_json_key(yaml_key):
    if isinstance(yaml_key, str) and '.' in yaml_key:
        return yaml_key.split('.')[-1]
    else:
        return yaml_key

def add_fields_to_struct(struct_string,go_var,go_type,json_key,toml_key):
    struct_string += str(go_var) + " " + str(go_type) + ' `json:"' + str(json_key) + ',omitempty" toml:"' +str(toml_key) + '"` ' + "\n"
    return struct_string

def generate_go_struct(struct_name, struct_data):
    struct_name="configurations" if struct_name == "" else struct_name
    struct_string = "type " + struct_name + " struct {\n"
    yaml_key=df['yaml_key'].str.split('.').str[-1]
    
    # base case: generate fields for the current struct level    
    for key, value in struct_data.items():
        selected_rows = df[yaml_key == key]

        if len(selected_rows) > 1:
            go_var = selected_rows['go_var'].values[1]
            toml_key = selected_rows['toml_key'].values[1]
            go_type=selected_rows['go_type'].values[1]
            json_key=selected_rows['json_key'].values[1]
        else:
            go_var = selected_rows['go_var'].values[0]
            toml_key = selected_rows['toml_key'].values[0]
            go_type=selected_rows['go_type'].values[0]
            json_key=selected_rows['json_key'].values[0]

        # add fields to the body of the struct
        struct_string=add_fields_to_struct(struct_string,go_var,go_type,json_key,toml_key)   

    struct_string += "}\n\n"
    
    # recursive case: generate struct definitions for nested structs
    for key, value in struct_data.items():
        selected_rows = df[yaml_key == key]

        if len(selected_rows) > 1:
            go_var = selected_rows['go_var'].values[1]
        else:
            go_var = selected_rows['go_var'].values[0]

        if isinstance(value, dict) and any(isinstance(v, dict) for v in value.values()):
            nested_struct_name = go_var
            nested_struct_data = value
            struct_string += generate_go_struct(nested_struct_name, nested_struct_data)
    
    return struct_string

# read excel
csv_file = "~/downloads/my_configs.csv"
df = pd.read_csv(csv_file)

# remove rows where all columns are nan
df = df.dropna(how='all')
# create the 'json_key' column using the custom function
df['json_key'] = df['yaml_key'].apply(extract_json_key)

data=df['yaml_key'].values.tolist() # read the 'yaml_key' column
data = pd.dataframe({'column':data}) # convert to dataframe

data=data['column'].str.split('.', expand=true) # split by '.'

nested_list = data.values.tolist() # convert to nested list
data=nested_list 

result_json = convert_to_dict(data) # convert to dict (json)

# the generated co code
go_struct = generate_go_struct("", result_json)

# write to file
file_path = "output.go"
with open(file_path, "w") as file:
    file.write(go_struct)

Das Problem ist (siehe unten Teil der CSV),

authentication.authenticator.basic
authentication.authenticator.basic.parameters
authentication.authenticator.basic.parameters.showAuthFailureReason
authentication.authenticator.basic.parameters.showAuthFailureReasonOnLoginPage
authentication.authenticator.totp
authentication.authenticator.totp.parameters
authentication.authenticator.totp.parameters.showAuthFailureReason
authentication.authenticator.totp.parameters.showAuthFailureReasonOnLoginPage
authentication.authenticator.totp.parameters.encodingMethod
authentication.authenticator.totp.parameters.timeStepSize

Hier, da es in der Spalte basictotp 字段 parameters 重复,因此脚本会混淆自身并生成两个 totpparameters 结构。预期结果是具有 basicparameterstotpparameters 结构。 csv 的 yaml_key viele ähnliche wiederholte Wörter gibt.

Ich weiß, dass das damit zu tun hat, dass der Index fest auf 1 in codiert ist go_var = selected_rows['go_var'].values[1], aber es ist schwer, das zu beheben.

Kann mir jemand eine Antwort geben? Ich denke,

  1. Probleme mit rekursiven Funktionen
  2. Es gibt ein Problem mit dem Code, der JSON generiert könnte die Hauptursache für dieses Problem sein.

Danke!

Ich habe auch versucht, chatgpt zu verwenden, aber da dies mit Verschachtelung und Rekursion zu tun hat, ist die von chatgpt bereitgestellte Antwort nicht sehr effizient.

Aktualisiert

Ich habe Duplikate in Spalten gefunden, die propertiespooloptionsendpointparameters 字段的行存在问题。这是因为它们在 yaml_key enthalten.

Lösung

Ich konnte dieses Problem lösen. Allerdings musste ich einen völlig neuen Ansatz für das Problem wählen, der darin bestand, eine Baumdatenstruktur zu verwenden und dann darüber zu iterieren. Das ist die Hauptlogik dahinter – https://www.geeksforgeeks.org/level-sequential tree traversal/

Dies ist der funktionierende Python-Code.

import pandas as pd
from collections import deque

structs=[]
class TreeNode:
    def __init__(self, name):
        self.name = name
        self.children = []
        self.path=""

    def add_child(self, child):
        self.children.append(child)

def create_tree(data):
    root = TreeNode('')
    for item in data:
        node = root
        for name in item.split('.'):
            existing_child = next((child for child in node.children if child.name == name), None)
            if existing_child:
                node = existing_child
            else:
                new_child = TreeNode(name)
                node.add_child(new_child)
                node = new_child
    return root

def generate_go_struct(struct_data):
    struct_name = struct_data['struct_name']
    fields = struct_data['fields']
    
    go_struct = f"type {struct_name} struct {{\n"

    for field in fields:
        field_name = field['name']
        field_type = field['type']
        field_default_val = str(field['default_val'])
        json_key=field['json_key']
        toml_key=field['toml_key']

        tail_part=f"\t{field_name} {field_type} `json:\"{json_key},omitempty\" toml:\"{toml_key}\"`\n\n"

        if pd.isna(field['default_val']):
            go_struct += tail_part
        else:
            field_default_val = "\t// +kubebuilder:default:=" + field_default_val
            go_struct += field_default_val + "\n" + tail_part

    go_struct += "}\n\n"
    return go_struct

def write_go_file(go_structs, file_path):
    with open(file_path, 'w') as file:
        for go_struct in go_structs:
            file.write(go_struct)

def create_new_struct(struct_name):
    struct_name = "Configurations" if struct_name == "" else struct_name
    struct_dict = {
        "struct_name": struct_name,
        "fields": []
    }
    
    return struct_dict

def add_field(struct_dict, field_name, field_type,default_val,json_key, toml_key):
    field_dict = {
        "name": field_name,
        "type": field_type,
        "default_val": default_val,
        "json_key":json_key,
        "toml_key":toml_key
    }
    struct_dict["fields"].append(field_dict)
    
    return struct_dict

def traverse_tree(root):
    queue = deque([root])  
    while queue:
        node = queue.popleft()
        filtered_df = df[df['yaml_key'] == node.path]
        go_var = filtered_df['go_var'].values[0] if not filtered_df.empty else None
        go_type = filtered_df['go_type'].values[0] if not filtered_df.empty else None

        if node.path=="":
            go_type="Configurations"

        # The structs themselves
        current_struct = create_new_struct(go_type)
        
        for child in node.children:  
            if (node.name!=""):
                child.path=node.path+"."+child.name   
            else:
                child.path=child.name

            filtered_df = df[df['yaml_key'] == child.path]
            go_var = filtered_df['go_var'].values[0] if not filtered_df.empty else None
            go_type = filtered_df['go_type'].values[0] if not filtered_df.empty else None
            default_val = filtered_df['default_val'].values[0] if not filtered_df.empty else None

            # Struct fields
            json_key = filtered_df['yaml_key'].values[0].split('.')[-1] if not filtered_df.empty else None
            toml_key = filtered_df['toml_key'].values[0].split('.')[-1] if not filtered_df.empty else None
            
            current_struct = add_field(current_struct, go_var, go_type,default_val,json_key, toml_key)

            if (child.children):
                # Add each child to the queue for processing
                queue.append(child)

        go_struct = generate_go_struct(current_struct)
        # print(go_struct,"\n")        
        structs.append(go_struct)

    write_go_file(structs, "output.go")

csv_file = "~/Downloads/my_configs.csv"
df = pd.read_csv(csv_file) 

sample_data=df['yaml_key'].values.tolist()

# Create the tree
tree = create_tree(sample_data)

# Traverse the tree
traverse_tree(tree)

Vielen Dank für Ihre Hilfe!

Das obige ist der detaillierte Inhalt vonKonvertieren Sie durch Punkte getrennte Werte mit Python in eine Go-Struktur. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen