MEDICAL OFFICE Forum

Forum-Navigation
ForumAktivität

Listenvariablen: nur letzten Eintrag ausgeben

Du musst dich anmelden um Beiträge und Themen zu erstellen.

Listenvariablen: nur letzten Eintrag ausgeben

Seite 1 von 2Nächste

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.  

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> 

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 Roland Steinmetz am 25. August 2026, 16:53 Uhr

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).

stimmt… hatte das „mit nur den letzten“ überlesen bzw. anders selektiv wahrgenommen

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?

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

Maximilian Kallenbach hat auf diesen Beitrag reagiert.
Maximilian Kallenbach

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.

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";
}

Das klingt nach Claude : )

Allerdings weiterhin das selbe Problem, plus die Umlautkodierung funktioniert nicht mehr

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.

Seite 1 von 2Nächste