rules = $rules; } /** * Extrahiert Metadaten aus den übergebenen Zeilen * * @param array $lines Array von Zeilen aus dem CSV-Header * @return array Extrahierte Metadaten */ public function extract(array $lines): array { $metadata = []; foreach ($this->rules as $rule) { // Validiere erforderliche Felder if (empty($rule['name']) || empty($rule['regex'])) { continue; } $ruleName = $rule['name']; $lineNumber = $rule['lineNumber'] ?? 1; $regex = $rule['regex']; // ✅ KORRIGIERT: Off-by-One Fix // config.json: "lineNumber": 1, 2, 3 (1-basiert, für Menschen lesbar) // PHP Arrays: $lines[0], $lines[1], $lines[2] (0-basiert) // Konvertierung: arrayIndex = lineNumber - 1 $arrayIndex = $lineNumber - 1; // Prüfe ob Zeile existiert if (!isset($lines[$arrayIndex])) { // Zeile existiert nicht - Debug-Info für Support DebugLogger::log('metadata_warning', "Extraction rule not found", [ 'rule_name' => $ruleName, 'expected_lineNumber' => $lineNumber, 'array_index' => $arrayIndex, 'available_lines' => count($lines) ]); continue; } $line = $lines[$arrayIndex]; // Regex mit '#' als Delimiter (erlaubt '/' in User-Patterns); '#' im Pattern escapen $pattern = '#' . str_replace('#', '\#', $regex) . '#u'; $matchResult = @preg_match_all($pattern, $line, $matches); if ($matchResult === false) { DebugLogger::log('metadata_error', "Invalid regex pattern", [ 'rule_name' => $ruleName, 'pattern' => $regex, ]); continue; } if ($matchResult === 0) { // Regex matched nicht auf dieser Zeile DebugLogger::log('metadata_warning', "Regex did not match", [ 'rule_name' => $ruleName, 'lineNumber' => $lineNumber, 'regex_pattern' => $regex, 'line_content' => substr($line, 0, 100) ]); continue; } // ✅ KORRIGIERT: captureGroup benutzen // captureGroup definiert welche Klammer-Gruppe extrahiert wird // 0 = komplette Match // 1 = erste Klammer-Gruppe (...) // 2 = zweite Klammer-Gruppe, etc. $captureGroup = isset($rule['captureGroup']) ? intval($rule['captureGroup']) : 1; // Sicherstellen dass die Capture Group existiert if (!isset($matches[$captureGroup]) || empty($matches[$captureGroup])) { // Fallback: Nutze komplette Match wenn Gruppe nicht existiert $metadata[$ruleName] = $matches[0][0] ?? ''; // echo "DEBUG: extraction_rule '{$ruleName}' - captureGroup {$captureGroup} not found, falling back to complete match\n"; } else { // Nutze die spezifische Capture Group $metadata[$ruleName] = $matches[$captureGroup][0] ?? ''; } DebugLogger::log('metadata', "Extraction rule applied", [ 'rule_name' => $ruleName, 'value' => $metadata[$ruleName] ?? null, ]); } return $metadata; } /** * Gibt die Anzahl der definierten Extraction-Rules zurück * * @return int Anzahl Rules */ public function getRuleCount(): int { return count($this->rules); } /** * Gibt alle definierten Extraction-Rules zurück * * @return array Die Rules */ public function getRules(): array { return $this->rules; } }