eigentlich wollte ich euch für dieses Projekt "nur" um ein Code Review bitten. Jetzt habe ich mich aber mit der Programmstruktur ziemlich verrannt und benötige etwas Hilfestellung.
Es geht bei dem Programm um folgendes. Es gibt eine Menge an Excel-Dateien mit Messwerten. Meine Aufgabe ist es, aus jeder Datei definierte Zellen auszulesen. In Spalte 1 steht die Beschreibung und in Spalte 2 der dazugehörige Wert.
Also das Programm bekommt die Beschreibung der Werte, liest den dazugehörigen Wert aus und schreibt die Beschreibung mit dem Wert in eine neue Datei. Das ganze für jede Datei die in dem festgelegten Ordner und Unterordner gefunden wurde und alle Beschreibungen enthält.
Es gibt neue und alte Dateien mit Messwerten und es ist nicht garantiert das in beiden Dateien die Beschreibung gleich benannt ist. Es kann sein, das in einer Datei "Volumen" steht und in der anderen "Volumn(xyz)" aber beides mal verbiergt sich dahinter der gesuchte Wert.
Wenn in einer Datei nicht alle gesuchten Beschreibungen gefunden werden, dann ignoriere ich die Datei bzw. schreibe es zur Info in eine Textdatei.
Das Programm funktioniert in einem Punkt nicht. Nehmen wir an in einer Zelle steht "Volumen(xy)" und die Beschreibung die der Benutzer zur Suche eingibt ist "Volumen". Dann findet mein Programm zwar die Zelle "Volumen(xy)" schreibt den Wert aber nicht in die neue Excel. Das macht es nicht, weil ich eine Funktion geschrieben habe, die erst mal die Datei nach den gewünschten Beschreibungen durchsucht und dann zwei Listen zurück gibt, Einmal mit den gefundenen Beschreibungen und einmal mit den nicht gefundenen Beschreibungen (wenn alles gut läuft ist die leer). Jetzt gehe ich hin und vergleiche wieder die Zellenbeschreibung mit dem Inhalt der zurückgegebenen Liste und wenn da was übereinstimmt, schreibe ich die Beschreibung mit Wert in ein Dictonary. Hier passiert auch der Fehler, in der Zelle steht "Volumen(xy)" und in der Liste "Volumen".
Wenn ich jetzt wieder mit verschachtelten 'for'-Schleifen und 're' die Beschreibungen durchsuche, dann mache ich zwei mal das Gleiche und das wirkt auf mich alles viel zu kompliziert und viel zu umständlich. Gerade sehe ich den Wald vor Bäumen nicht mehr und würde mich freuen wenn ihr mir sagen könntet, wie ihr vorgehen würdet. Gerne auch nur in Worte und ich schaue wie ich das in Code umsetze.
Für ein Code-Review ist es jetzt noch zu früh, weil ich befürchte dass ich da noch mal einiges ändern muss. (Dennoch bin ich für jede Anmerkung offen, auch wenn ich noch nicht fertig bin).
Naja jetzt hier mal meinen Code, das bringt vermutlich mehr wie mein getexte:
Code: Alles auswählen
#!/usr/bin/env python3
import re
import tkinter as tk
from datetime import datetime
from pathlib import Path
from tkinter import messagebox, ttk
from tkinter.filedialog import askdirectory
from openpyxl import Workbook, load_workbook
WORKBOOK_WITH_READ_DATA = "Ausgelesene Werte.xlsx"
INFO_FILE = "Nicht gelesene Dateien.txt"
DEFAULT_CELL_NAMES = "Volumen, Drehzahl, Gas"
class App(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
master.columnconfigure(0, weight=100)
self.user_select = tk.StringVar()
self.user_select.set("<Kein Oderne ausgewählt>")
ttk.Label(self, text="Ausgewählter Ordner:").grid(row=0, column=0, sticky=tk.W)
self.selected_folder = tk.Label(self, textvariable=self.user_select)
self.selected_folder.grid(row=1, column=0, sticky=tk.W)
ttk.Button(self, text="Ordner auswählen", command=self.open_dialog).grid(
row=2, column=0, sticky=tk.W
)
ttk.Label(self, text="Zellennamen die ausgelesen werden sollen").grid(
row=0, column=4, sticky=tk.W
)
ttk.Label(self, text="getrennt mit Komma eingeben:").grid(
row=1, column=4, sticky=tk.W
)
self.cells_to_read = tk.StringVar()
self.cells_to_read.set(DEFAULT_CELL_NAMES)
ttk.Entry(self, textvariable=self.cells_to_read).grid(
row=2, column=4, sticky=tk.W
)
ttk.Button(self, text="Auslesen", command=self.control_read_write_data).grid(
row=5, column=5
)
ttk.Button(self, text="Beenden", command=self.quit).grid(
row=5, column=4, sticky=tk.E
)
self.coffee = ttk.Label(self, text="Zeit für Kaffee...")
self.process_bar = ttk.Progressbar(self)
self.timestamp = None
self.folder_path = None
self.info_file = False
@property
def keywords(self):
return [keyword.strip() for keyword in self.cells_to_read.get().split(",")]
def open_dialog(self):
self.folder_path = Path(askdirectory(mustexist=True))
self.user_select.set(self.folder_path.name)
def control_read_write_data(self):
self.timestamp = datetime.now().strftime("%Y%m%d_%H%M")
if not self.folder_path:
messagebox.showerror(title="Oh nein!", message="Kein Ordner ausgewählt")
else:
self.coffee.grid(row=4, column=2, columnspan=2, sticky=tk.W)
self.process_bar.grid(row=4, column=4, sticky=tk.W)
self.process_bar.start(10)
for file in self.folder_path.glob("**/*.xlsx"):
if not [
name
for name in file.name.split("_")
if name == WORKBOOK_WITH_READ_DATA
]:
keyword_to_cell_content = self.read_file(file)
if keyword_to_cell_content:
self.write_read_data_to_file(keyword_to_cell_content)
self.process_bar.stop()
self.process_bar.grid_forget()
self.coffee.grid_forget()
if self.info_file:
messagebox.showinfo(
"Info Datei",
"Nicht alle gefundenen Dateien konnten gelesen werden, bitte Info-Datei beachten.",
)
self.info_file = False
def check_file_for_keywords(self, rows):
founded_keywords = []
not_founded_keywords = []
for row, _ in rows:
for keyword in self.keywords:
_keyword = re.search(rf"\b{keyword}\b", row.value, re.IGNORECASE)
if _keyword:
founded_keywords.append(_keyword.group().lower())
for keyword in self.keywords:
if keyword.casefold() not in founded_keywords:
not_founded_keywords.append(keyword)
print(f'founded_keywords: {founded_keywords}')
return founded_keywords, not_founded_keywords
def write_info_file(self, file, not_founded_keywords):
with (self.folder_path / f"{self.timestamp}_{INFO_FILE}").open(
"a", encoding="UTF-8"
) as info_file:
info_file.write(
f'-> In der Datei "{file}" wurden folgende Suchwörter nicht gefunden: {not_founded_keywords}'
)
self.info_file = True
def read_file(self, file):
keyword_to_cell_content = {}
worksheet = load_workbook(file)["Tabelle1"]
founded_keywords, not_founded_keywords = self.check_file_for_keywords(
worksheet.iter_rows(min_col=1, max_col=2)
)
if not len(not_founded_keywords):
for description, cell_value in worksheet.iter_rows(min_col=1, max_col=2):
print(f'description.value: {description.value}')
if str(description.value).lower() in founded_keywords:
keyword_to_cell_content[description.value] = cell_value.value
else:
self.write_info_file(file, not_founded_keywords)
print(f'keyword_to_cell_content: {keyword_to_cell_content}')
return keyword_to_cell_content
def write_read_data_to_file(self, keyword_to_file):
file_path = self.folder_path / f"{self.timestamp}_{WORKBOOK_WITH_READ_DATA}"
if file_path.exists():
workbook = load_workbook(file_path)
else:
workbook = Workbook()
worksheet = workbook.active
for key in keyword_to_file:
worksheet.append([key, keyword_to_file[key]])
workbook.save(file_path)
def main():
root = tk.Tk()
root.title("Auswertung")
app = App(root)
app.pack()
app.mainloop()
if __name__ == "__main__":
main()
Code: Alles auswählen
founded_keywords: ['volumen', 'drehzahl', 'gas']
description.value: l
description.value: Volumen (xy)
description.value: j
description.value: drehzahl
description.value: Gas
description.value: Apfel
keyword_to_cell_content: {'drehzahl': 33, 'Gas': 'H2'}
Vielen Dank vorab.
Grüße
Dennis