erste Fassung eines SKripts zur Extraktion der Texte aus einer .dxf Datei erstellt
This commit is contained in:
@@ -10,12 +10,14 @@ set PROJECT_LIB=%PROJECT%\lib
|
||||
set PROJECT_DATA=%PROJECT%\data
|
||||
set PROJECT_WORK=%PROJECT%\work
|
||||
set PROJECT_TEST=%PROJECT%\testdata
|
||||
set PROJECT_TRANSLATION=%PROJECT%\translation
|
||||
|
||||
set SIVAS_TEILESTAMM=\\195.243.223.3\sivas\jit\programme\KSbExcelExportSivasTeilestamm.exe
|
||||
set SIVAS_EXCEL_EXPORT_DIR=%PROJECT_DATA%
|
||||
|
||||
if not exist %PROJECT%\work mkdir %PROJECT%\work
|
||||
if not exist %PROJECT%\data mkdir %PROJECT%\data
|
||||
if not exist %PROJECT%\translation mkdir %PROJECT%\translation
|
||||
|
||||
set PROJECT_IO_RESULTS=Z:\Automatisierung\Konvertierungstools\4_io-Konvertierer
|
||||
set PROJECT_BOM_RESULTS=Z:\Automatisierung\Konvertierungstools\3_Kabellaengen-Konvertierer
|
||||
@@ -26,6 +28,7 @@ if exist "%~dp0_setenv.bat" (
|
||||
call "%~dp0_setenv.bat"
|
||||
)
|
||||
|
||||
REM Prüfe ob PATH bereits erweitert wurde
|
||||
set PATH=%PROJECT_BIN%;%PATH%
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -22,5 +22,5 @@ export PROJECT_IO_RESULTS=$PROJECT_WORK
|
||||
export PROJECT_BOM_RESULTS=$PROJECT_WORK
|
||||
export INSTALL_DIR="$HOME/kabeltool"
|
||||
|
||||
# Add project bin to PATH
|
||||
# Add project bin to PATH (only if not already added)
|
||||
export PATH="$PROJECT_BIN:$PATH"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
CALL manage_interpreter.bat activate_interpreter
|
||||
python %PROJECT_LIB%\translate.py %*
|
||||
CALL manage_interpreter.bat deactivate_interpreter
|
||||
@@ -0,0 +1,35 @@
|
||||
[ignore_pattern_wildcard]
|
||||
# Wildcard-Muster für Texte die NICHT in die Excel Datei geschrieben werden sollen
|
||||
# Ein Muster pro Zeile
|
||||
# Wildcards: * (mehrere Zeichen), ? (ein Zeichen)
|
||||
# Format: pattern_name = muster
|
||||
|
||||
# Häufige technische Abkürzungen und Codes
|
||||
layer = LAYER=*
|
||||
dim = DIM*
|
||||
special = %%*
|
||||
|
||||
# Koordinaten und technische Angaben
|
||||
coord_x = X=*
|
||||
coord_y = Y=*
|
||||
coord_z = Z=*
|
||||
|
||||
|
||||
[ignore_pattern_regex]
|
||||
# Reguläre Ausdrücke für Texte die NICHT in die Excel Datei geschrieben werden sollen
|
||||
# Ein Ausdruck pro Zeile (Python regex Syntax)
|
||||
# Format: pattern_name = regex
|
||||
|
||||
# Formeln wie =A1 +AB12
|
||||
formula = ^=A\d\s*\+[A-Z]{2}\d+
|
||||
|
||||
# Technische Angaben
|
||||
height = ^\\H1.875x
|
||||
millimeter = ^\d+\s*mm$
|
||||
m_numbers = ^M\d{3}$
|
||||
|
||||
# Koordinaten mit Pfeilen
|
||||
coord_arrows = ^\+\d{1,3}(?:[.,]\d{3})\s*(?:<<<|>>>)\s*\+\d{1,3}(?:[.,]\d{3})$
|
||||
# +UC3206\P3 x ET200 SP DI16 402.0
|
||||
uc4 = ^\+UC\d{4}
|
||||
uc2 = ^=A\d\+UC\d{2}
|
||||
@@ -0,0 +1,272 @@
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from configparser import ConfigParser
|
||||
from fnmatch import fnmatch
|
||||
|
||||
import ezdxf
|
||||
from openpyxl import Workbook
|
||||
|
||||
|
||||
"""
|
||||
Dieses Programm:
|
||||
- liest eine DXF Datei und sammelt alle TEXT und MTEXT Objekte
|
||||
- schreibt diese in die erste Spalte einer Excel-Datei
|
||||
- speichert die Excel-Datei im PROJECT_WORK Verzeichnis
|
||||
"""
|
||||
|
||||
|
||||
def check_environment_var(env_str: str) -> Path:
|
||||
"""Prüft ob eine Umgebungsvariable gesetzt ist und gibt den Pfad zurück."""
|
||||
out_path = os.environ.get(env_str)
|
||||
if out_path:
|
||||
return Path(out_path)
|
||||
else:
|
||||
print(f"Umgebungsvariable {env_str} ist nicht gesetzt oder leer.")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def load_ignore_patterns(cfg_path: Path) -> tuple[list[str], list[str]]:
|
||||
"""
|
||||
Liest die ignore_pattern aus der translator.cfg Datei.
|
||||
Unterstützt sowohl Wildcard-Muster (*,?) als auch reguläre Ausdrücke.
|
||||
|
||||
Args:
|
||||
cfg_path: Pfad zum Konfigurationsverzeichnis (PROJECT_CFG)
|
||||
|
||||
Returns:
|
||||
Tuple mit (Wildcard-Mustern, Regex-Mustern)
|
||||
"""
|
||||
config_file = cfg_path / "translator.cfg"
|
||||
|
||||
if not config_file.exists():
|
||||
print(f"FEHLER: Konfigurationsdatei nicht gefunden: {config_file}")
|
||||
print(f"Bitte erstellen Sie die Datei 'translator.cfg' im Verzeichnis: {cfg_path}")
|
||||
sys.exit(1)
|
||||
|
||||
config = ConfigParser()
|
||||
try:
|
||||
config.read(config_file, encoding='utf-8')
|
||||
except Exception as e:
|
||||
print(f"Fehler beim Lesen der Konfigurationsdatei: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
wildcard_patterns = []
|
||||
regex_patterns = []
|
||||
|
||||
# Lade Wildcard-Muster
|
||||
if config.has_section('ignore_pattern_wildcard'):
|
||||
for key in config['ignore_pattern_wildcard']:
|
||||
pattern = config['ignore_pattern_wildcard'][key].strip()
|
||||
if pattern and not pattern.startswith('#'):
|
||||
wildcard_patterns.append(pattern)
|
||||
|
||||
# Lade Regex-Muster
|
||||
if config.has_section('ignore_pattern_regex'):
|
||||
for key in config['ignore_pattern_regex']:
|
||||
pattern = config['ignore_pattern_regex'][key].strip()
|
||||
if pattern and not pattern.startswith('#'):
|
||||
regex_patterns.append(pattern)
|
||||
|
||||
print(f"Geladene Wildcard-Muster: {len(wildcard_patterns)}")
|
||||
for pattern in wildcard_patterns:
|
||||
print(f" - {pattern}")
|
||||
|
||||
print(f"Geladene Regex-Muster: {len(regex_patterns)}")
|
||||
for pattern in regex_patterns:
|
||||
print(f" - {pattern}")
|
||||
|
||||
return wildcard_patterns, regex_patterns
|
||||
|
||||
|
||||
def should_ignore_text(text: str, wildcard_patterns: list[str], regex_patterns: list[str]) -> bool:
|
||||
"""
|
||||
Prüft ob ein Text ignoriert werden soll basierend auf den Mustern.
|
||||
|
||||
Args:
|
||||
text: Zu prüfender Text
|
||||
wildcard_patterns: Liste der Wildcard-Muster (*,?)
|
||||
regex_patterns: Liste der regulären Ausdrücke
|
||||
|
||||
Returns:
|
||||
True wenn Text ignoriert werden soll, False sonst
|
||||
"""
|
||||
# Prüfe Wildcard-Muster
|
||||
for pattern in wildcard_patterns:
|
||||
if fnmatch(text, pattern):
|
||||
return True
|
||||
|
||||
# Prüfe Regex-Muster
|
||||
for pattern in regex_patterns:
|
||||
try:
|
||||
if re.search(pattern, text):
|
||||
return True
|
||||
except re.error:
|
||||
# Falls ungültiger Regex, ignoriere dieses Muster
|
||||
print(f"WARNUNG: Ungültiger regulärer Ausdruck: {pattern}")
|
||||
continue
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def extract_text_from_dxf(filename: Path, wildcard_patterns: list[str], regex_patterns: list[str]) -> list[str]:
|
||||
"""
|
||||
Extrahiert alle TEXT und MTEXT Objekte aus einer DXF Datei.
|
||||
Verwendet ein Set, um Duplikate zu vermeiden.
|
||||
|
||||
Args:
|
||||
filename: Pfad zur DXF Datei
|
||||
wildcard_patterns: Liste der Wildcard-Muster zum Filtern
|
||||
regex_patterns: Liste der Regex-Muster zum Filtern
|
||||
|
||||
Returns:
|
||||
Alphabetisch sortierte Liste mit allen gefundenen Texten (nach Filterung, ohne Duplikate)
|
||||
"""
|
||||
texts_set = set() # Set für eindeutige Texte
|
||||
ignored_count = 0
|
||||
total_count = 0
|
||||
|
||||
try:
|
||||
doc = ezdxf.readfile(filename)
|
||||
msp = doc.modelspace()
|
||||
|
||||
# Sammle alle TEXT Objekte
|
||||
for entity in msp.query('TEXT'):
|
||||
if entity.dxf.text:
|
||||
total_count += 1
|
||||
text = entity.dxf.text
|
||||
if should_ignore_text(text, wildcard_patterns, regex_patterns):
|
||||
ignored_count += 1
|
||||
else:
|
||||
texts_set.add(text)
|
||||
|
||||
# Sammle alle MTEXT Objekte
|
||||
for entity in msp.query('MTEXT'):
|
||||
if entity.text:
|
||||
total_count += 1
|
||||
text = entity.text
|
||||
if should_ignore_text(text, wildcard_patterns, regex_patterns):
|
||||
ignored_count += 1
|
||||
else:
|
||||
texts_set.add(text)
|
||||
|
||||
# Konvertiere Set zu sortierter Liste
|
||||
texts = sorted(texts_set)
|
||||
|
||||
print(f"Anzahl gefundener TEXT/MTEXT Objekte: {total_count}")
|
||||
print(f"Ignorierte Texte (nach Filter): {ignored_count}")
|
||||
print(f"Duplikate entfernt: {total_count - ignored_count - len(texts)}")
|
||||
print(f"Eindeutige Texte für Export: {len(texts)}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fehler beim Lesen der DXF Datei: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
return texts
|
||||
|
||||
|
||||
def write_texts_to_excel(texts: list[str], output_path: Path):
|
||||
"""
|
||||
Schreibt die Texte in die erste Spalte einer Excel-Datei.
|
||||
|
||||
Args:
|
||||
texts: Liste der zu schreibenden Texte
|
||||
output_path: Pfad zur Ausgabe-Excel-Datei
|
||||
"""
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "Texte"
|
||||
|
||||
# Kopfzeile
|
||||
ws['A1'] = "Text"
|
||||
|
||||
# Texte in die erste Spalte schreiben
|
||||
for idx, text in enumerate(texts, start=2):
|
||||
ws[f'A{idx}'] = text
|
||||
|
||||
# Spaltenbreite anpassen
|
||||
ws.column_dimensions['A'].width = 50
|
||||
|
||||
try:
|
||||
wb.save(output_path)
|
||||
print(f"Excel-Datei erfolgreich erstellt: {output_path}")
|
||||
except Exception as e:
|
||||
print(f"Fehler beim Schreiben der Excel-Datei: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Extrahiert TEXT und MTEXT Objekte aus einer DXF Datei und schreibt sie in eine Excel-Datei',
|
||||
prog='translate'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-f', '--filename',
|
||||
action='store',
|
||||
required=True,
|
||||
help='DXF Datei die verarbeitet werden soll',
|
||||
metavar='myfile.dxf'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-e', '--extract',
|
||||
action='store_true',
|
||||
required=True,
|
||||
help='Hole alle Texte aus der .dxf in eine Excel Datei'
|
||||
)
|
||||
parser.add_argument(
|
||||
'-o', '--outname',
|
||||
action='store',
|
||||
help='Name der Ausgabedatei (ohne Pfad, mit oder ohne .xlsx Endung)',
|
||||
metavar='output.xlsx'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Prüfe Umgebungsvariablen
|
||||
work_dir = check_environment_var('PROJECT_WORK')
|
||||
cfg_dir = check_environment_var('PROJECT_CFG')
|
||||
|
||||
# Lade Ignore-Muster aus Konfigurationsdatei
|
||||
wildcard_patterns, regex_patterns = load_ignore_patterns(cfg_dir)
|
||||
|
||||
# Prüfe ob Datei eine DXF Datei ist
|
||||
input_filename = args.filename
|
||||
if not input_filename.lower().endswith(('.dxf', '.dwg')):
|
||||
print("Nur verfügbar für .dxf oder .dwg Dateien")
|
||||
sys.exit(1)
|
||||
|
||||
# Versuche zuerst Datei im Work-Ordner zu finden
|
||||
filename = work_dir / input_filename
|
||||
if not filename.exists():
|
||||
# Falls nicht gefunden, prüfe ob es ein vollständiger Pfad ist
|
||||
filename = Path(input_filename)
|
||||
if not filename.exists():
|
||||
print(f"Datei nicht gefunden: {input_filename}")
|
||||
print(f" Geprüft in Work-Ordner: {work_dir / input_filename}")
|
||||
print(f" Geprüft als vollständiger Pfad: {filename}")
|
||||
sys.exit(1)
|
||||
|
||||
# Extrahiere Texte aus DXF
|
||||
if args.extract:
|
||||
print(f"Lese DXF Datei: {filename}")
|
||||
texts = extract_text_from_dxf(filename, wildcard_patterns, regex_patterns)
|
||||
|
||||
# Erstelle Output-Dateinamen
|
||||
if args.outname:
|
||||
# Verwende benutzerdefinierten Namen
|
||||
output_filename = args.outname
|
||||
# Füge .xlsx Endung hinzu falls nicht vorhanden
|
||||
if not output_filename.endswith('.xlsx'):
|
||||
output_filename += '.xlsx'
|
||||
else:
|
||||
# Standardname basierend auf Eingabedatei
|
||||
output_filename = filename.stem + "_texts.xlsx"
|
||||
|
||||
output_path = work_dir / output_filename
|
||||
|
||||
# Schreibe Texte in Excel
|
||||
write_texts_to_excel(texts, output_path)
|
||||
|
||||
print("Verarbeitung erfolgreich abgeschlossen.")
|
||||
Reference in New Issue
Block a user