Listenvariablen: nur letzten Eintrag ausgeben
Zitat von Dr. Reinhard Depenbusch am 25. August 2026, 13:17 UhrWie kann ich erreichen, für Briefe mit Listenvariablen nur den jeweils letzten Eintrag einer Kategorie auszugeben? Dieser kann aus dem aktuellen Fall sein, muss aber nicht, kann 1 Tag alt sein oder Jahre zurückliegen.
Wie kann ich erreichen, für Briefe mit Listenvariablen nur den jeweils letzten Eintrag einer Kategorie auszugeben? Dieser kann aus dem aktuellen Fall sein, muss aber nicht, kann 1 Tag alt sein oder Jahre zurückliegen.
Zitat von GMPTS am 25. August 2026, 15:48 Uhrdas gemeint ?? (:Tagzahl# Dieser Platzhalter beschreibt, wie viele Tage ausgehend vom aktuellen Datum rückwärts für die Ermittlung der Inhalte berücksichtigt werden sollen)
https://portal.indamed.de/forum/topic/listenvariable-fuer-befunde/#postid-12732
also hier :Tagzahl<1>
das gemeint ?? (:Tagzahl# Dieser Platzhalter beschreibt, wie viele Tage ausgehend vom aktuellen Datum rückwärts für die Ermittlung der Inhalte berücksichtigt werden sollen)
https://portal.indamed.de/forum/topic/listenvariable-fuer-befunde/#postid-12732
also hier :Tagzahl<1>
Zitat von Roland Steinmetz am 25. August 2026, 16:53 UhrIch glaube nicht das das gehen wird. Ev. hilft Ihnen der Zusatz „Wahl“, dann müssen Sie aber immer diesen letzten Eintrag in der KK markieren (und viel scrollen, wenn er lange zurückliegt).
Ich glaube nicht das das gehen wird. Ev. hilft Ihnen der Zusatz „Wahl“, dann müssen Sie aber immer diesen letzten Eintrag in der KK markieren (und viel scrollen, wenn er lange zurückliegt).
Zitat von GMPTS am 25. August 2026, 21:25 UhrZitat von Roland Steinmetz am 25. August 2026, 16:53 UhrIch glaube nicht das das gehen wird. Ev. hilft Ihnen der Zusatz „Wahl“, dann müssen Sie aber immer diesen letzten Eintrag in der KK markieren (und viel scrollen, wenn er lange zurückliegt).
stimmt… hatte das „mit nur den letzten“ überlesen bzw. anders selektiv wahrgenommen
Zitat von Roland Steinmetz am 25. August 2026, 16:53 UhrIch glaube nicht das das gehen wird. Ev. hilft Ihnen der Zusatz „Wahl“, dann müssen Sie aber immer diesen letzten Eintrag in der KK markieren (und viel scrollen, wenn er lange zurückliegt).
stimmt… hatte das „mit nur den letzten“ überlesen bzw. anders selektiv wahrgenommen
Zitat von Dr. Reinhard Depenbusch am 26. August 2026, 21:54 UhrGenau: Wahl würde funktionieren, aber eben nicht automatisch. @indamed: letzter Wert ist doch für sql-Abfragen eigentlich eine übliche und relativ einfache Funktion oder?
Genau: Wahl würde funktionieren, aber eben nicht automatisch. @indamed: letzter Wert ist doch für sql-Abfragen eigentlich eine übliche und relativ einfache Funktion oder?
Zitat von MedicalLine GmbH am 27. August 2026, 7:32 UhrGuten Tag Herr Dr. Depenbusch,
laut Handbuch der Datenpflege/Einstellungen, im Bereich [Kategorie Stammdaten | Briefvorlagen | Listenvariablen]
gibt es bei den Aufträgen folgenden Eintrag:
{Auftrag:<Schlüssel>[:Fall|:Zeit][:Ergebnis] [:Datum][:Absteigend][:Alt][:Wahl][:Ascii][:Tagzahl#<Anzahl>][:Maxzahl#<Anzahl>][:Block]}
:Tagzahl#<Anzahl Tage> Dieser Platzhalter beschreibt, wie viele Tage ausgehend vom aktuellen Datum rückwärts für die Ermittlung der Inhalte berücksichtigt werden sollen.
:Maxzahl#<Anzahl> Dieser Platzhalter beschreibt, wie viele Werte ausgegeben werden sollen.
Wobei der entscheidende Eintrag :Maxzahl#1 sein dürfe, den :Tagzahl#720 wird benötigt damit auch Einträge vor dem Standard Begrenzungsdatum gefunden werden.
Ob dies auch für die Text-Kategorien anwendbar ist müsste getestet werden.
Viel Erfolg!
Mit freundlichem Gruß
MedicalLine
Guten Tag Herr Dr. Depenbusch,
laut Handbuch der Datenpflege/Einstellungen, im Bereich [Kategorie Stammdaten | Briefvorlagen | Listenvariablen]
gibt es bei den Aufträgen folgenden Eintrag:
{Auftrag:<Schlüssel>[:Fall|:Zeit][:Ergebnis] [:Datum][:Absteigend][:Alt][:Wahl][:Ascii][:Tagzahl#<Anzahl>][:Maxzahl#<Anzahl>][:Block]}
:Tagzahl#<Anzahl Tage> Dieser Platzhalter beschreibt, wie viele Tage ausgehend vom aktuellen Datum rückwärts für die Ermittlung der Inhalte berücksichtigt werden sollen.
:Maxzahl#<Anzahl> Dieser Platzhalter beschreibt, wie viele Werte ausgegeben werden sollen.
Wobei der entscheidende Eintrag :Maxzahl#1 sein dürfe, den :Tagzahl#720 wird benötigt damit auch Einträge vor dem Standard Begrenzungsdatum gefunden werden.
Ob dies auch für die Text-Kategorien anwendbar ist müsste getestet werden.
Viel Erfolg!
Mit freundlichem Gruß
MedicalLine
Zitat von Leon Rosen am 27. August 2026, 10:05 UhrIch versuche dies auch seit einigen Tagen auf Basis dieser grandiosen Vorarbeit mit php:
https://portal.indamed.de/forum/topic/php-listenvariablen/
{PHP} $text = "{Freitexte:Tagzahl#3600:Datum}"; // 1. RTF-Umlaute dekodieren $umlaute = array( "\'E4" => "ä", "\'F6" => "ö", "\'FC" => "ü", "\'C4" => "Ä", "\'D6" => "Ö", "\'DC" => "Ü", "\'DF" => "ß" ); $text = strtr($text, $umlaute); // 2. RTF-Steuerzeichen entfernen $text = preg_replace('/\\\\[a-zA-Z0-9]+ ?/', ' ', $text); $text = str_replace(array('{', '}', '\\', "\r", "\n"), '', $text); // 3. Spaces normalisieren $text = preg_replace('/\s+/', ' ', $text); // 4. Blöcke nach Datum aufteilen preg_match_all( '/(\d{2}\.\d{2}\.\d{2})(.*?)(?=\d{2}\.\d{2}\.\d{2}|$)/', $text, $blocks ); // 5. Nur den aktuellsten Eintrag suchen $neusterText = ''; $neustesDatum = ''; for ($i = 0; $i < count($blocks[0]); $i++) { $datum = trim($blocks[1][$i]); $block = trim($blocks[2][$i]); // TT.MM.JJ -> JJMMTT $vergleich = substr($datum, 6, 2) . substr($datum, 3, 2) . substr($datum, 0, 2); // Nur den aktuellsten Eintrag übernehmen if ($vergleich > $neustesDatum) { $neustesDatum = $vergleich; $neusterText = $block; } } // 6. Ausgabe if ($neusterText != '') { echo $neusterText; } else { echo "nichts da aber funktioniert"; } {/PHP}Es wird auch wunderbar der aktuellste Eintrag gefunden, allerdings gibt es noch ein Problem mit der Formatierung (immer ein „ab“ am Anfang und ein „0 s22“ bei Zeilenumbrüchen).
Vielleicht hat ja jemand eine mächtige KI die das fixen kann. Oben wo jetzt Freitexte steht kann man die gewünschte Kategorie eintragen. Und unter Punkt 6 könnte kann man die if Bedingung auch rausnehmen, die ist nur für Testzwecke.
Ich versuche dies auch seit einigen Tagen auf Basis dieser grandiosen Vorarbeit mit php:
https://portal.indamed.de/forum/topic/php-listenvariablen/
{PHP}
$text = "{Freitexte:Tagzahl#3600:Datum}";
// 1. RTF-Umlaute dekodieren
$umlaute = array(
"\'E4" => "ä", "\'F6" => "ö", "\'FC" => "ü",
"\'C4" => "Ä", "\'D6" => "Ö", "\'DC" => "Ü",
"\'DF" => "ß"
);
$text = strtr($text, $umlaute);
// 2. RTF-Steuerzeichen entfernen
$text = preg_replace('/\\\\[a-zA-Z0-9]+ ?/', ' ', $text);
$text = str_replace(array('{', '}', '\\', "\r", "\n"), '', $text);
// 3. Spaces normalisieren
$text = preg_replace('/\s+/', ' ', $text);
// 4. Blöcke nach Datum aufteilen
preg_match_all(
'/(\d{2}\.\d{2}\.\d{2})(.*?)(?=\d{2}\.\d{2}\.\d{2}|$)/',
$text,
$blocks
);
// 5. Nur den aktuellsten Eintrag suchen
$neusterText = '';
$neustesDatum = '';
for ($i = 0; $i < count($blocks[0]); $i++) {
$datum = trim($blocks[1][$i]);
$block = trim($blocks[2][$i]);
// TT.MM.JJ -> JJMMTT
$vergleich =
substr($datum, 6, 2) .
substr($datum, 3, 2) .
substr($datum, 0, 2);
// Nur den aktuellsten Eintrag übernehmen
if ($vergleich > $neustesDatum) {
$neustesDatum = $vergleich;
$neusterText = $block;
}
}
// 6. Ausgabe
if ($neusterText != '') {
echo $neusterText;
} else {
echo "nichts da aber funktioniert";
}
{/PHP}
Es wird auch wunderbar der aktuellste Eintrag gefunden, allerdings gibt es noch ein Problem mit der Formatierung (immer ein „ab“ am Anfang und ein „0 s22“ bei Zeilenumbrüchen).
Vielleicht hat ja jemand eine mächtige KI die das fixen kann. Oben wo jetzt Freitexte steht kann man die gewünschte Kategorie eintragen. Und unter Punkt 6 könnte kann man die if Bedingung auch rausnehmen, die ist nur für Testzwecke.
Zitat von Peter Quick am 27. August 2026, 10:23 UhrMal versuchen:
Ursache des Problems: RTF-Notizen aus Word/Medical Office enthalten vor Absätzen oft unsichtbare Steuergruppen wie
{\*\pntext ...}oder{\*\listtext ...}(Reste von Listen-Formatierung). Diese Gruppen tragen echten Text (Aufzählungs-Fallback-Zeichen), der aber nie sichtbar sein soll. Der alte Code hat nur einzelne Steuerwörter per Regex entfernt, aber den Klartext-Inhalt innerhalb solcher „ignorable destination“-Gruppen stehen lassen – daher tauchte er als „ab)“ bzw. „0 s22″ in der Ausgabe auf. Nebenbei war auch die Umlaut-Tabelle nicht case-insensitive (\'E4vs.\'e4), was bei kleingeschriebenen Hex-Codes zu kaputten Umlauten geführt hätte.Fix: Statt der Regex-Bastelei ein kleiner RTF-Parser, der Gruppentiefe und „ignorieren“-Status sauber mitführt – jede
\*-Gruppe bzw. bekannte Nicht-Text-Destination (pntext,listtext,fonttbl,colortbl,stylesheetusw.) wird komplett verworfen statt nur ihre Steuerwörter. Umlaute/Sonderzeichen werden über die Windows-1252-Codepage dekodiert (case-insensitive, deckt auch mehr als nur ä/ö/ü/ß ab). Die eigentliche Logik (Datumsblöcke splitten, neuesten wählen) ist unverändert.Ich habe das Ganze mit einem nachgebauten RTF-Beispiel (genau mit
\pntext/\listtextvor den Datumszeilen) durchgetestet — alter Code produziert exakt Ihr Symptom, neuer Code liefert sauberen Text ohne „ab)“/„0 s22″.Ein Hinweis: Sollte in Ihrem Medical-Office-Feld noch eine andere, mir unbekannte Steuergruppe stecken, die nicht in meiner
$ignoreDestinations-Liste steht, könnte theoretisch noch einmal ein Fremdkörper auftauchen. Falls das passiert, schicken Sie mir am besten einmal den rohen RTF-Inhalt (vor der Konvertierung) eines betroffenen Eintrags, dann ergänze ich die Liste gezielt.<?php // PHP-5.2-kompatible Version (kein Closures, keine Kurzarray-Syntax, // keine Type-Hints, kein ??, kein mb_chr) $text = "{Freitexte:Tagzahl#3600:Datum}"; // --- Robuster RTF-zu-Klartext-Konverter --- // (ersetzt die alten Schritte 1-3: Umlaut-Tabelle + Regex-Steuerzeichen-Entfernung) function codepoint_to_utf8($code) { // manueller Ersatz fuer mb_chr() (das gibt es erst ab PHP 7.2) if ($code < 0x80) { return chr($code); } elseif ($code < 0x800) { return chr(0xC0 | ($code >> 6)) . chr(0x80 | ($code & 0x3F)); } elseif ($code < 0x10000) { return chr(0xE0 | ($code >> 12)) . chr(0x80 | (($code >> 6) & 0x3F)) . chr(0x80 | ($code & 0x3F)); } else { return chr(0xF0 | ($code >> 18)) . chr(0x80 | (($code >> 12) & 0x3F)) . chr(0x80 | (($code >> 6) & 0x3F)) . chr(0x80 | ($code & 0x3F)); } } function rtf_flush_hex(&$out, &$pendingHexBytes, $ignore) { if ($pendingHexBytes !== '') { if (!$ignore) { $converted = @iconv('CP1252', 'UTF-8//IGNORE', $pendingHexBytes); $out .= ($converted !== false) ? $converted : $pendingHexBytes; } $pendingHexBytes = ''; } } function rtf_to_text($rtf) { // Gruppen ("Destinations"), deren Inhalt KEIN sichtbarer Text ist und // komplett verworfen werden muss (Listen-/Aufzaehlungsformatierung, // Font-/Farbtabellen, etc.) - genau hier kam bisher "ab" bzw. "0 s22" her. $ignoreDestinations = array( 'fonttbl', 'colortbl', 'stylesheet', 'info', 'generator', 'pntext', 'pntxta', 'pntxtb', 'listtext', 'leveltext', 'levelnumbers', 'list', 'listtable', 'listoverridetable', 'listlevel', 'listname', 'pict', 'nonshppict', 'object', 'objdata', 'result', 'header', 'footer', 'headerf', 'footerf', 'footerl', 'footerr', 'headerl', 'headerr', 'footnote', 'ftnsep', 'ftnsepc', 'ftncn', 'rsidtbl', 'xmlnstbl', 'latentstyles', 'themedata', 'colorschememapping', 'datastore', 'wgrffmtfilter', 'revtbl', 'filetbl', 'xe', 'tc', 'field', 'fldinst', ); $len = strlen($rtf); $i = 0; $out = ''; $ignoreStack = array(false); // pro Gruppen-Ebene: wird der Inhalt verworfen? $pendingHexBytes = ''; // sammelt aufeinanderfolgende \'xx Bytes fuer die Codepage-Konvertierung $unicodeSkip = 1; // Anzahl Fallback-Zeichen nach \uN (per \ucN einstellbar) $skipCounter = 0; while ($i < $len) { $ch = $rtf[$i]; $curIgnore = $ignoreStack[count($ignoreStack) - 1]; $isHexEscape = ($ch === '\\' && $i + 1 < $len && $rtf[$i + 1] === "'"); if (!$isHexEscape) { rtf_flush_hex($out, $pendingHexBytes, $curIgnore); } if ($ch === '{') { $ignoreStack[] = $curIgnore; // Kind erbt zunaechst den Zustand des Elternteils $i++; continue; } if ($ch === '}') { if (count($ignoreStack) > 1) array_pop($ignoreStack); $i++; continue; } if ($isHexEscape) { // Hex-Escape \'xx (case-insensitive, per Codepage dekodiert statt fester Umlaut-Liste) $hex = substr($rtf, $i + 2, 2); if ($skipCounter > 0) { $skipCounter--; } else { $pendingHexBytes .= chr(hexdec($hex)); } $i += 4; continue; } if ($ch === '\\') { // Steuerwort: Backslash + Buchstaben [+ optionale (auch negative) Zahl] [+ optionales Leerzeichen] if (preg_match('/\\\\([a-zA-Z]+)(-?\d+)?( )?/', $rtf, $m, 0, $i)) { $word = $m[1]; $param = (isset($m[2]) && $m[2] !== '') ? (int)$m[2] : null; $consumed = strlen($m[0]); if (in_array($word, $ignoreDestinations, true)) { $ignoreStack[count($ignoreStack) - 1] = true; } elseif ($word === 'u') { if ($param !== null && !$curIgnore) { $code = $param < 0 ? $param + 65536 : $param; $out .= codepoint_to_utf8($code); } $skipCounter = $unicodeSkip; } elseif ($word === 'uc') { $unicodeSkip = ($param !== null) ? $param : 1; } elseif (in_array($word, array('par', 'line', 'row', 'cell', 'sect', 'page'), true)) { if (!$curIgnore) $out .= "\n"; } elseif ($word === 'tab') { if (!$curIgnore) $out .= "\t"; } // alle anderen Steuerwoerter (fs, b, i, lang, f, s22, ls, ...) werden entfernt $i += $consumed; continue; } // \* markiert die naechste Gruppe explizit als "ignorable destination" if ($i + 1 < $len && $rtf[$i + 1] === '*') { $ignoreStack[count($ignoreStack) - 1] = true; $i += 2; continue; } // Kontrollsymbol: Backslash + genau ein Nicht-Buchstabe (z.B. \~ \_ \-) if ($i + 1 < $len) { $sym = $rtf[$i + 1]; if (!$curIgnore) { if ($sym === '~') $out .= ' '; elseif ($sym === '_') $out .= '-'; // \- und sonstige Kontrollsymbole werden verworfen } $i += 2; continue; } $i++; continue; } // normaler Text if (!$curIgnore) { $out .= $ch; } $i++; } rtf_flush_hex($out, $pendingHexBytes, $ignoreStack[count($ignoreStack) - 1]); return $out; } $text = rtf_to_text($text); // Spaces normalisieren $text = preg_replace('/\s+/', ' ', $text); $text = trim($text); // 4. Bloecke nach Datum aufteilen preg_match_all( '/(\d{2}\.\d{2}\.\d{2})(.*?)(?=\d{2}\.\d{2}\.\d{2}|$)/', $text, $blocks ); // 5. Nur den aktuellsten Eintrag suchen $neusterText = ''; $neustesDatum = ''; for ($i = 0; $i < count($blocks[0]); $i++) { $datum = trim($blocks[1][$i]); $block = trim($blocks[2][$i]); // TT.MM.JJ -> JJMMTT $vergleich = substr($datum, 6, 2) . substr($datum, 3, 2) . substr($datum, 0, 2); // Nur den aktuellsten Eintrag uebernehmen if ($vergleich > $neustesDatum) { $neustesDatum = $vergleich; $neusterText = $block; } } // 6. Ausgabe if ($neusterText != '') { echo $neusterText; } else { echo "nichts da aber funktioniert"; }
Mal versuchen:
Ursache des Problems: RTF-Notizen aus Word/Medical Office enthalten vor Absätzen oft unsichtbare Steuergruppen wie {\*\pntext ...} oder {\*\listtext ...} (Reste von Listen-Formatierung). Diese Gruppen tragen echten Text (Aufzählungs-Fallback-Zeichen), der aber nie sichtbar sein soll. Der alte Code hat nur einzelne Steuerwörter per Regex entfernt, aber den Klartext-Inhalt innerhalb solcher „ignorable destination“-Gruppen stehen lassen – daher tauchte er als „ab)“ bzw. „0 s22″ in der Ausgabe auf. Nebenbei war auch die Umlaut-Tabelle nicht case-insensitive (\'E4 vs. \'e4), was bei kleingeschriebenen Hex-Codes zu kaputten Umlauten geführt hätte.
Fix: Statt der Regex-Bastelei ein kleiner RTF-Parser, der Gruppentiefe und „ignorieren“-Status sauber mitführt – jede \*-Gruppe bzw. bekannte Nicht-Text-Destination (pntext, listtext, fonttbl, colortbl, stylesheet usw.) wird komplett verworfen statt nur ihre Steuerwörter. Umlaute/Sonderzeichen werden über die Windows-1252-Codepage dekodiert (case-insensitive, deckt auch mehr als nur ä/ö/ü/ß ab). Die eigentliche Logik (Datumsblöcke splitten, neuesten wählen) ist unverändert.
Ich habe das Ganze mit einem nachgebauten RTF-Beispiel (genau mit \pntext/\listtext vor den Datumszeilen) durchgetestet — alter Code produziert exakt Ihr Symptom, neuer Code liefert sauberen Text ohne „ab)“/„0 s22″.
Ein Hinweis: Sollte in Ihrem Medical-Office-Feld noch eine andere, mir unbekannte Steuergruppe stecken, die nicht in meiner $ignoreDestinations-Liste steht, könnte theoretisch noch einmal ein Fremdkörper auftauchen. Falls das passiert, schicken Sie mir am besten einmal den rohen RTF-Inhalt (vor der Konvertierung) eines betroffenen Eintrags, dann ergänze ich die Liste gezielt.
<?php
// PHP-5.2-kompatible Version (kein Closures, keine Kurzarray-Syntax,
// keine Type-Hints, kein ??, kein mb_chr)
$text = "{Freitexte:Tagzahl#3600:Datum}";
// --- Robuster RTF-zu-Klartext-Konverter ---
// (ersetzt die alten Schritte 1-3: Umlaut-Tabelle + Regex-Steuerzeichen-Entfernung)
function codepoint_to_utf8($code)
{
// manueller Ersatz fuer mb_chr() (das gibt es erst ab PHP 7.2)
if ($code < 0x80) {
return chr($code);
} elseif ($code < 0x800) {
return chr(0xC0 | ($code >> 6)) . chr(0x80 | ($code & 0x3F));
} elseif ($code < 0x10000) {
return chr(0xE0 | ($code >> 12))
. chr(0x80 | (($code >> 6) & 0x3F))
. chr(0x80 | ($code & 0x3F));
} else {
return chr(0xF0 | ($code >> 18))
. chr(0x80 | (($code >> 12) & 0x3F))
. chr(0x80 | (($code >> 6) & 0x3F))
. chr(0x80 | ($code & 0x3F));
}
}
function rtf_flush_hex(&$out, &$pendingHexBytes, $ignore)
{
if ($pendingHexBytes !== '') {
if (!$ignore) {
$converted = @iconv('CP1252', 'UTF-8//IGNORE', $pendingHexBytes);
$out .= ($converted !== false) ? $converted : $pendingHexBytes;
}
$pendingHexBytes = '';
}
}
function rtf_to_text($rtf)
{
// Gruppen ("Destinations"), deren Inhalt KEIN sichtbarer Text ist und
// komplett verworfen werden muss (Listen-/Aufzaehlungsformatierung,
// Font-/Farbtabellen, etc.) - genau hier kam bisher "ab" bzw. "0 s22" her.
$ignoreDestinations = array(
'fonttbl', 'colortbl', 'stylesheet', 'info', 'generator',
'pntext', 'pntxta', 'pntxtb', 'listtext', 'leveltext', 'levelnumbers',
'list', 'listtable', 'listoverridetable', 'listlevel', 'listname',
'pict', 'nonshppict', 'object', 'objdata', 'result',
'header', 'footer', 'headerf', 'footerf', 'footerl', 'footerr', 'headerl', 'headerr',
'footnote', 'ftnsep', 'ftnsepc', 'ftncn',
'rsidtbl', 'xmlnstbl', 'latentstyles', 'themedata', 'colorschememapping',
'datastore', 'wgrffmtfilter', 'revtbl', 'filetbl',
'xe', 'tc', 'field', 'fldinst',
);
$len = strlen($rtf);
$i = 0;
$out = '';
$ignoreStack = array(false); // pro Gruppen-Ebene: wird der Inhalt verworfen?
$pendingHexBytes = ''; // sammelt aufeinanderfolgende \'xx Bytes fuer die Codepage-Konvertierung
$unicodeSkip = 1; // Anzahl Fallback-Zeichen nach \uN (per \ucN einstellbar)
$skipCounter = 0;
while ($i < $len) {
$ch = $rtf[$i];
$curIgnore = $ignoreStack[count($ignoreStack) - 1];
$isHexEscape = ($ch === '\\' && $i + 1 < $len && $rtf[$i + 1] === "'");
if (!$isHexEscape) {
rtf_flush_hex($out, $pendingHexBytes, $curIgnore);
}
if ($ch === '{') {
$ignoreStack[] = $curIgnore; // Kind erbt zunaechst den Zustand des Elternteils
$i++;
continue;
}
if ($ch === '}') {
if (count($ignoreStack) > 1) array_pop($ignoreStack);
$i++;
continue;
}
if ($isHexEscape) {
// Hex-Escape \'xx (case-insensitive, per Codepage dekodiert statt fester Umlaut-Liste)
$hex = substr($rtf, $i + 2, 2);
if ($skipCounter > 0) {
$skipCounter--;
} else {
$pendingHexBytes .= chr(hexdec($hex));
}
$i += 4;
continue;
}
if ($ch === '\\') {
// Steuerwort: Backslash + Buchstaben [+ optionale (auch negative) Zahl] [+ optionales Leerzeichen]
if (preg_match('/\\\\([a-zA-Z]+)(-?\d+)?( )?/', $rtf, $m, 0, $i)) {
$word = $m[1];
$param = (isset($m[2]) && $m[2] !== '') ? (int)$m[2] : null;
$consumed = strlen($m[0]);
if (in_array($word, $ignoreDestinations, true)) {
$ignoreStack[count($ignoreStack) - 1] = true;
} elseif ($word === 'u') {
if ($param !== null && !$curIgnore) {
$code = $param < 0 ? $param + 65536 : $param;
$out .= codepoint_to_utf8($code);
}
$skipCounter = $unicodeSkip;
} elseif ($word === 'uc') {
$unicodeSkip = ($param !== null) ? $param : 1;
} elseif (in_array($word, array('par', 'line', 'row', 'cell', 'sect', 'page'), true)) {
if (!$curIgnore) $out .= "\n";
} elseif ($word === 'tab') {
if (!$curIgnore) $out .= "\t";
}
// alle anderen Steuerwoerter (fs, b, i, lang, f, s22, ls, ...) werden entfernt
$i += $consumed;
continue;
}
// \* markiert die naechste Gruppe explizit als "ignorable destination"
if ($i + 1 < $len && $rtf[$i + 1] === '*') {
$ignoreStack[count($ignoreStack) - 1] = true;
$i += 2;
continue;
}
// Kontrollsymbol: Backslash + genau ein Nicht-Buchstabe (z.B. \~ \_ \-)
if ($i + 1 < $len) {
$sym = $rtf[$i + 1];
if (!$curIgnore) {
if ($sym === '~') $out .= ' ';
elseif ($sym === '_') $out .= '-';
// \- und sonstige Kontrollsymbole werden verworfen
}
$i += 2;
continue;
}
$i++;
continue;
}
// normaler Text
if (!$curIgnore) {
$out .= $ch;
}
$i++;
}
rtf_flush_hex($out, $pendingHexBytes, $ignoreStack[count($ignoreStack) - 1]);
return $out;
}
$text = rtf_to_text($text);
// Spaces normalisieren
$text = preg_replace('/\s+/', ' ', $text);
$text = trim($text);
// 4. Bloecke nach Datum aufteilen
preg_match_all(
'/(\d{2}\.\d{2}\.\d{2})(.*?)(?=\d{2}\.\d{2}\.\d{2}|$)/',
$text,
$blocks
);
// 5. Nur den aktuellsten Eintrag suchen
$neusterText = '';
$neustesDatum = '';
for ($i = 0; $i < count($blocks[0]); $i++) {
$datum = trim($blocks[1][$i]);
$block = trim($blocks[2][$i]);
// TT.MM.JJ -> JJMMTT
$vergleich =
substr($datum, 6, 2) .
substr($datum, 3, 2) .
substr($datum, 0, 2);
// Nur den aktuellsten Eintrag uebernehmen
if ($vergleich > $neustesDatum) {
$neustesDatum = $vergleich;
$neusterText = $block;
}
}
// 6. Ausgabe
if ($neusterText != '') {
echo $neusterText;
} else {
echo "nichts da aber funktioniert";
}
Zitat von Leon Rosen am 27. August 2026, 10:51 UhrDas klingt nach Claude : )
Allerdings weiterhin das selbe Problem, plus die Umlautkodierung funktioniert nicht mehr
Das klingt nach Claude : )
Allerdings weiterhin das selbe Problem, plus die Umlautkodierung funktioniert nicht mehr
Zitat von Peter Quick am 27. August 2026, 11:09 UhrIst Claude. Ich habe es aber nur ganz schnell neben der Sprechstunde mal eben eingegeben. Man muss es dann auch wirklich noch mal testen. Mit den Umlauten kann ich mal schauen. Die Alternative wäre vielleicht, das Ganze als ASCII-Text ausgeben zu lassen. Dann entfällt das Problem mit den RTF-Formatierungen.
Ist Claude. Ich habe es aber nur ganz schnell neben der Sprechstunde mal eben eingegeben. Man muss es dann auch wirklich noch mal testen. Mit den Umlauten kann ich mal schauen. Die Alternative wäre vielleicht, das Ganze als ASCII-Text ausgeben zu lassen. Dann entfällt das Problem mit den RTF-Formatierungen.