305 lines
9.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Konvertiert die IHK-Projektdokumentation von Markdown nach Word (DOCX)
mit IHK-konformen Formatierungen.
"""
import os
import re
from docx import Document
from docx.shared import Pt, Inches, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING
from docx.enum.style import WD_STYLE_TYPE
from markdown import markdown
from bs4 import BeautifulSoup
import html2text
def create_ihk_styles(doc):
"""Erstellt IHK-konforme Formatvorlagen"""
# Normaler Text
normal_style = doc.styles['Normal']
normal_style.font.name = 'Arial'
normal_style.font.size = Pt(11)
normal_style.paragraph_format.line_spacing_rule = WD_LINE_SPACING.ONE_POINT_FIVE
normal_style.paragraph_format.space_after = Pt(6)
normal_style.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
# Überschrift 1
h1_style = doc.styles['Heading 1']
h1_style.font.name = 'Arial'
h1_style.font.size = Pt(16)
h1_style.font.bold = True
h1_style.paragraph_format.space_before = Pt(12)
h1_style.paragraph_format.space_after = Pt(12)
h1_style.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.LEFT
# Überschrift 2
h2_style = doc.styles['Heading 2']
h2_style.font.name = 'Arial'
h2_style.font.size = Pt(14)
h2_style.font.bold = True
h2_style.paragraph_format.space_before = Pt(12)
h2_style.paragraph_format.space_after = Pt(6)
h2_style.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.LEFT
# Überschrift 3
h3_style = doc.styles['Heading 3']
h3_style.font.name = 'Arial'
h3_style.font.size = Pt(12)
h3_style.font.bold = True
h3_style.paragraph_format.space_before = Pt(6)
h3_style.paragraph_format.space_after = Pt(6)
h3_style.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.LEFT
# Code-Style
try:
code_style = doc.styles.add_style('Code', WD_STYLE_TYPE.CHARACTER)
code_style.font.name = 'Courier New'
code_style.font.size = Pt(10)
except:
code_style = doc.styles['Code']
return doc
def setup_document_layout(doc):
"""Richtet das Dokumentlayout nach IHK-Vorgaben ein"""
sections = doc.sections
for section in sections:
# Seitenränder (IHK-Standard)
section.top_margin = Inches(1.0)
section.bottom_margin = Inches(1.0)
section.left_margin = Inches(1.25)
section.right_margin = Inches(1.0)
# Seitengröße A4
section.page_height = Inches(11.69)
section.page_width = Inches(8.27)
def add_title_page(doc):
"""Fügt die Titelseite hinzu"""
# Titel
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
p.add_run('Abschlussprüfung - Sommer 2025\n').bold = True
p.add_run('\n')
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
p.add_run('Fachinformatiker für digitale Vernetzung\n').font.size = Pt(14)
doc.add_paragraph()
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
p.add_run('Dokumentation der betrieblichen Projektarbeit\n').font.size = Pt(16)
doc.add_paragraph()
# Projekttitel
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = p.add_run('MYP Manage Your Printer\n')
run.font.size = Pt(18)
run.font.bold = True
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
p.add_run('Digitalisierung des 3D-Drucker-Reservierungsprozesses durch Etablierung\n')
p.add_run('der cyberphysischen Kommunikation mit relevanten Hardwarekomponenten')
# Mehrere Leerzeilen
for _ in range(5):
doc.add_paragraph()
# Abgabedatum
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
p.add_run('Abgabedatum: 5. Juni 2025').bold = True
doc.add_paragraph()
doc.add_paragraph()
# Ausbildungsbetrieb
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.LEFT
p.add_run('Ausbildungsbetrieb\n').bold = True
p.add_run('\n')
p.add_run('Mercedes-Benz AG\n')
p.add_run('Daimlerstraße 143\n')
p.add_run('D-12277 Berlin')
doc.add_paragraph()
# Prüfungsbewerber
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.LEFT
p.add_run('Prüfungsbewerber\n').bold = True
p.add_run('\n')
p.add_run('Till Tomczak\n')
p.add_run('Hainbuchenstraße 19\n')
p.add_run('D-16761 Hennigsdorf')
# Seitenumbruch nach Titelseite
doc.add_page_break()
def process_markdown_content(content):
"""Verarbeitet Markdown-Inhalt und strukturiert ihn für Word"""
# Entferne Bilder vorerst
content = re.sub(r'<img[^>]*>', '', content)
# Teile den Inhalt in Abschnitte
lines = content.split('\n')
processed_content = []
skip_until_content = False
for line in lines:
# Skip Titelbereich
if line.strip().startswith('# Inhaltsverzeichnis'):
skip_until_content = True
continue
if skip_until_content and line.strip().startswith('# 1. Einleitung'):
skip_until_content = False
if not skip_until_content and not line.strip().startswith('Mercedes-Benz') and \
not line.strip().startswith('Till Tomczak') and \
not line.strip().startswith('Abgabedatum:'):
processed_content.append(line)
return '\n'.join(processed_content)
def add_content_to_document(doc, content):
"""Fügt den Inhalt zum Word-Dokument hinzu"""
lines = content.split('\n')
current_paragraph = None
in_code_block = False
for line in lines:
# Überschrift 1
if line.startswith('# '):
heading = line[2:].strip()
doc.add_heading(heading, level=1)
current_paragraph = None
# Überschrift 2
elif line.startswith('## '):
heading = line[3:].strip()
doc.add_heading(heading, level=2)
current_paragraph = None
# Überschrift 3
elif line.startswith('### '):
heading = line[4:].strip()
doc.add_heading(heading, level=3)
current_paragraph = None
# Überschrift 4
elif line.startswith('#### '):
heading = line[5:].strip()
# Word hat standardmäßig nur 3 Heading-Ebenen, nutze fetten Text
p = doc.add_paragraph()
p.add_run(heading).bold = True
current_paragraph = None
# Aufzählungen
elif line.strip().startswith('- '):
text = line.strip()[2:]
p = doc.add_paragraph(text, style='List Bullet')
current_paragraph = None
# Normaler Text
elif line.strip():
if current_paragraph is None:
current_paragraph = doc.add_paragraph()
else:
current_paragraph.add_run(' ')
# Verarbeite Inline-Formatierungen
process_inline_formatting(current_paragraph, line)
# Leerzeile
else:
current_paragraph = None
def process_inline_formatting(paragraph, text):
"""Verarbeitet Inline-Formatierungen wie fett und kursiv"""
# Ersetze Markdown-Formatierungen
parts = re.split(r'(\*\*[^*]+\*\*|\*[^*]+\*|`[^`]+`)', text)
for part in parts:
if part.startswith('**') and part.endswith('**'):
# Fett
paragraph.add_run(part[2:-2]).bold = True
elif part.startswith('*') and part.endswith('*') and not part.startswith('**'):
# Kursiv
paragraph.add_run(part[1:-1]).italic = True
elif part.startswith('`') and part.endswith('`'):
# Code
run = paragraph.add_run(part[1:-1])
run.font.name = 'Courier New'
run.font.size = Pt(10)
else:
# Normaler Text
paragraph.add_run(part)
def add_table_of_contents(doc):
"""Fügt ein Inhaltsverzeichnis hinzu"""
doc.add_heading('Inhaltsverzeichnis', level=1)
# Platzhalter für automatisches Inhaltsverzeichnis
p = doc.add_paragraph()
p.add_run('[Das Inhaltsverzeichnis wird in Word automatisch generiert.\n')
p.add_run('Verwenden Sie: Verweise → Inhaltsverzeichnis → Automatisches Verzeichnis]')
p.italic = True
doc.add_page_break()
def main():
"""Hauptfunktion"""
# Pfade
input_file = 'Dokumentation_Final_Markdown/Dokumentation.md'
output_file = 'IHK_Projektdokumentation_Final.docx'
# Lese Markdown-Datei
print("Lese Markdown-Datei...")
with open(input_file, 'r', encoding='utf-8') as f:
content = f.read()
# Erstelle Word-Dokument
print("Erstelle Word-Dokument...")
doc = Document()
# Richte Styles und Layout ein
print("Konfiguriere IHK-konforme Formatierung...")
create_ihk_styles(doc)
setup_document_layout(doc)
# Füge Titelseite hinzu
print("Erstelle Titelseite...")
add_title_page(doc)
# Füge Inhaltsverzeichnis hinzu
print("Füge Inhaltsverzeichnis hinzu...")
add_table_of_contents(doc)
# Verarbeite und füge Hauptinhalt hinzu
print("Verarbeite Dokumentinhalt...")
processed_content = process_markdown_content(content)
add_content_to_document(doc, processed_content)
# Speichere Dokument
print(f"Speichere Dokument als {output_file}...")
doc.save(output_file)
print("Konvertierung abgeschlossen!")
print("\nHinweise zur Nachbearbeitung:")
print("1. Überprüfen Sie die Formatierung und passen Sie sie ggf. an")
print("2. Generieren Sie das Inhaltsverzeichnis neu (Verweise → Inhaltsverzeichnis aktualisieren)")
print("3. Fügen Sie Kopf- und Fußzeilen mit Seitenzahlen hinzu")
print("4. Überprüfen Sie die Seitenumbrüche")
print("5. Fügen Sie ggf. Abbildungen und Diagramme ein")
if __name__ == "__main__":
main()