クリニクス

久山町スコアを電子カルテ記載から自動計算できるように改良しました


1. はじめに

久山町スコアは、日本人における10年間の動脈硬化性疾患(心筋梗塞や脳梗塞など)の発症リスクを予測するスコアリングシステムです。久山町研究に基づき、日本人の特性を反映したリスク評価が可能であり、特に生活習慣病の管理や動脈硬化性疾患の予防に役立ちます。以前のブログ記事TextBlazeを利用したスニペットを紹介した際は患者情報を手入力する必要がありました。休日を利用して電子カルテから自動抽出できるように改良しましたので紹介します。電子カルテ記載からの情報抽出を独立したスニペットでできるようにしたので他のスニペットでも利用できるようになりました。


2. 久山町スコアとは?

久山町スコアは、以下の因子を評価し、心血管疾患リスクを予測するものです。

スコア計算に用いる因子

  1. 年齢
  2. 性別
  3. 収縮期血圧(SBP)
  4. HDLコレステロール(HDL-C)
  5. LDLコレステロール(LDL-C)
  6. 喫煙歴
  7. 糖代謝異常(糖尿病含む)
  8. 既往歴(冠動脈疾患・脳梗塞など)

このスコアを基に、以下の3段階のリスク分類を行います。

リスク分類10年間の動脈硬化性疾患発症リスク
低リスク2%未満
中リスク2%~10%未満
高リスク10%以上

3. 電子カルテ(クリニクス)からのデータ抽出

電子カルテ(クリニクス)の記載から、Text Blaze の extractregex() および testregex() を活用してデータを自動取得します。Text Blazeのweb importerを利用します。抽出用コード全体は

{note: preview=no}{chart={site: text; selector=.css-8u2jis; page=https://karte.medley.life/*}}{run: age=extractregex({site: text; selector=.names-age},"(..)歳")
sei=extractregex({site: text; selector=.names-age},"(.)性")
sex={=sei}&"性"
`高血圧`= testregex(chart,"(#|#|♯)\s*高血圧|HT|若年性高血圧")
`脂質異常症`=testregex(chart,"(#|#|♯)\\s*(高コレステロール血症|脂質異常|脂質代謝異常|高トリグリセライド血症|高TG血症|家族性高コレステロール血症|高脂血症)")
`糖尿病`=testregex(chart,"(#|#|♯)\\s*(糖尿病|1型糖尿病|2型糖尿病|境界型糖尿病|DM|Diabetes)")
`冠動脈疾患`=testregex(chart,"(#|#|♯)\\s*(冠動脈疾患|狭心症|心筋梗塞|冠攣縮性狭心症|冠動脈狭窄|(不安定)?\\s*狭心症|(陳旧性)?\\s*心筋梗塞|冠動脈硬化)")
`脳血管疾患`=testregex(chart, "(#|#|♯)\\s*(脳血管疾患|脳梗塞|一過性脳虚血発作|脳卒中|陳旧性脳梗塞|脳梗塞後遺症)")
`慢性腎臓病`=testregex(chart, "(#|#|♯)\\s*(慢性腎臓病|CKD|慢性腎不全|腎機能低下|糖尿病性腎症|慢性腎障害)")
`末梢血管疾患`=testregex(chart, "(#|#|♯)\\s*(末梢血管疾患|ASO|閉塞性動脈硬化症|重症下肢虚血|下肢閉塞性動脈硬化症|バージャ病)")
`虚血性心疾患/脳梗塞`=testregex(chart,"(#|#|♯)\\s*(冠動脈疾患|狭心症|心筋梗塞|冠攣縮性狭心症|冠動脈狭窄|(不安定)?\\s*狭心症|(陳旧性)?\\s*心筋梗塞|冠動脈硬化|脳血管疾患|脳梗塞|一過性脳虚血発作|脳卒中|陳旧性脳梗塞|脳梗塞後遺症)")
 `喫煙`= testregex(chart,"(#|#|♯)\s*喫煙|タバコ|禁煙できない")
 `飲酒`= testregex(chart,"(#|#|♯)\s*飲酒|お酒|アルコール")
 `height`=extractregex(chart, "身長\\D{0,8}([0-9]{1,5}(?:\\.[0-9]{1,2})?)", "i")
 `weight`=extractregex(chart, "体重\\D{0,8}([0-9]{1,5}(?:\\.[0-9]{1,2})?)", "i")}
{run: wbc=extractregex({=chart},"白血球数\s*[HL]?\s*([\d.]+)\s*/MCL")
rbc=extractregex({=chart},"赤血球数\s*[HL]?\s*([\d.]+)\s*X10000/MCL")
hgb=extractregex({=chart},"血色素量\s*[HL]?\s*([\d.]+)\s*G/DL")
hct=extractregex({=chart},"ヘマトクリット\s*[HL]?\s*([\d.]+)\s*%")
mcv=extractregex({=chart},"MCV\s*[HL]?\s*([\d.]+)\s*FL")
mch=extractregex({=chart},"MCH\s*[HL]?\s*([\d.]+)\s*PG")
mchc=extractregex({=chart},"MCHC\s*[HL]?\s*([\d.]+)\s*%")
plt=extractregex({=chart},"血小板数\s*[HL]?\s*([\d.]+)\s*X10000/MCL")
myelocyte=extractregex({=chart},"骨髄球\s*[HL]?\s*([\d.]+)\s*%")
metamyelocyte=extractregex({=chart},"後骨髄球\s*[HL]?\s*([\d.]+)\s*%")
neutrophil=extractregex({=chart},"好中球\s*[HL]?\s*([\d.]+)\s*%")
eosinophil=extractregex({=chart},"好酸球\s*[HL]?\s*([\d.]+)\s*%")
basophil=extractregex({=chart},"好塩基球\s*[HL]?\s*([\d.]+)\s*%")
lymphocyte=extractregex({=chart},"リンパ球\s*[HL]?\s*([\d.]+)\s*%")
monocyte=extractregex({=chart},"単球\s*[HL]?\s*([\d.]+)\s*%")
atypical_lymphocyte=extractregex({=chart},"異型リンパ球\s*[HL]?\s*([\d.]+)\s*%")
ast=extractregex({=chart},"AST\(GOT\)\s*[HL]?\s*([\d.]+)\s*U/L")
alt=extractregex({=chart},"ALT\(GPT\)\s*[HL]?\s*([\d.]+)\s*U/L")
ggtp=extractregex({=chart},"γ-GT\s*[HL]?\s*([\d.]+)\s*U/L")
ck=extractregex({=chart},"CK\(CPK\)\s*[HL]?\s*([\d.]+)\s*U/L")
amylase=extractregex({=chart},"アミラーゼ\s*[HL]?\s*([\d.]+)\s*U/L")
bilirubin=extractregex({=chart},"総ビリルビン\s*[HL]?\s*([\d.]+)\s*MG/DL")
tp=extractregex({=chart},"総蛋白\s*[HL]?\s*([\d.]+)\s*G/DL")
alb=extractregex({=chart},"アルブミン\s*[HL]?\s*([\d.]+)\s*G/DL")
ag_ratio=extractregex({=chart},"A/G比\s*[HL]?\s*([\d.]+)")
tg=extractregex({=chart},"中性脂肪\s*[HL]?\s*([\d.]+)\s*MG/DL")
hdl=extractregex({=chart},"HDLコレステロール\s*[HL]?\s*([\d.]+)\s*MG/DL")
ldl=extractregex({=chart},"LDLコレステロール\s*[HL]?\s*([\d.]+)\s*MG/DL")
bun=extractregex({=chart},"尿素窒素\s*[HL]?\s*([\d.]+)\s*MG/DL")
ua=extractregex({=chart},"尿酸\s*[HL]?\s*([\d.]+)\s*MG/DL")
cre=extractregex({=chart},"クレアチニン\s*[HL]?\s*([\d.]+)\s*MG/DL")
egfr=extractregex({=chart},"eGFRcreat\s*[HL]?\s*([\d.]+)\s*ML/MIN/1.73")
na=extractregex({=chart},"ナトリウム\s*[HL]?\s*([\d.]+)\s*MEQ/L")
k=extractregex({=chart},"カリウム\s*[HL]?\s*([\d.]+)\s*MEQ/L")
cl=extractregex({=chart},"クロール\s*[HL]?\s*([\d.]+)\s*MEQ/L")
glucose=extractregex({=chart},"血糖\s*[HL]?\s*([\d.]+)\s*MG/DL")
hba1c=extractregex({=chart},"HbA1c\s*NGSP\s*[HL]?\s*([\d.]+)\s*%")
ferritin=extractregex({=chart},"フェリチン\s*[HL]?\s*([\d.]+)\s*NG/ML")
}{endnote}

となっています。コード解説しますと

(1) 基本情報の抽出

まず、年齢と性別を電子カルテから取得します。runコマンドを使用することにより後でパラメーターを設定し直すことできます。

{run: age=extractregex({site: text; selector=.names-age},"(..)歳")
sei=extractregex({site: text; selector=.names-age},"(.)性")
sex={=sei}&"性"}

(2) 生活習慣病や既往歴の取得

カルテの診断名(例:#糖尿病、#高血圧)から、該当する疾患を自動判定します。

`高血圧`= testregex(chart,"(#|#|♯)\s*高血圧|HT|若年性高血圧")
`糖尿病`=testregex(chart,"(#|#|♯)\\s*(糖尿病|DM|Diabetes)")
`冠動脈疾患`=testregex(chart,"(#|#|♯)\\s*(冠動脈疾患|狭心症|心筋梗塞)")
`脳血管疾患`=testregex(chart, "(#|#|♯)\\s*(脳血管疾患|脳梗塞|一過性脳虚血発作)")
`慢性腎臓病`=testregex(chart, "(#|#|♯)\\s*(慢性腎臓病|CKD|腎機能低下)")
`喫煙`= testregex(chart,"(#|#|♯)\s*喫煙|タバコ|禁煙できない")

この方法により、電子カルテの記載から診断名を抽出し、手入力の手間を省きます。

(3) バイタルサイン・検査データの取得

`sbp`=extractregex(chart,"収縮期血圧\s*([\d.]+)\s*MMHG")
`dbp`=extractregex(chart,"拡張期血圧\s*([\d.]+)\s*MMHG")
tg=extractregex({=chart},"中性脂肪\s*[HL]?\s*([\d.]+)\s*MG/DL")
hdl=extractregex({=chart},"HDLコレステロール\s*[HL]?\s*([\d.]+)\s*MG/DL")
ldl=extractregex({=chart},"LDLコレステロール\s*[HL]?\s*([\d.]+)\s*MG/DL")

これにより、血圧や脂質異常症の情報を電子カルテから自動取得し、久山町スコアの計算に活用できます。


4. 久山町スコアの計算

電子カルテから取得したデータを基に、Text Blaze でスコア計算を行います。コード全体は

{import: /imf}久山町スコア{note}年齢:{formtext: name=age; default=45; cols=2}歳、性別:{formmenu: default=男性; 女性; name=sex}、{formtoggle: name=糖尿病; default=no}{endformtoggle}、{formtoggle: name=慢性腎臓病; default=no}{endformtoggle}、{formtoggle: name=末梢血管疾患; default=no}{endformtoggle}、{formtoggle: name=虚血性心疾患/脳梗塞; default=}{endformtoggle}、血圧:{formtext: name=sbp; default=130; cols=3}/{formtext: name=dbp; default=75; cols=3}mmHg、糖代謝異常:{formtoggle: name=糖代謝異常(糖尿病は含まない); default=no}{endformtoggle}、LDL-C:{formtext: name=ldl; default=150; cols=3}mg/dl、HDL-C:{formtext: name=hdl; default=50; cols=3}mg/dl、{formtoggle: name=喫煙; default=no}{endformtoggle}{endnote}{if: sex=="男性"}{sex_score=7}{else}{sex_score=0}{endif}①性別:{=sex_score}
{if: sbp<120 }{bp_score=0}{elseif: sbp<130}{bp_score=1}{elseif: sbp<140}{bp_score=2}{elseif: sbp<160}{bp_score=3}{else}{bp_score=4}{endif}②血圧:{=bp_score}
{if: `糖代謝異常(糖尿病は含まない)`==no}{dm_score=0}{else}{dm_score=1}{endif}③糖代謝異常:{=dm_score}
{if: ldl<120}{ldl_score=0}{elseif: ldl<140}{ldl_score=1}{elseif: ldl<160}{ldl_score=2}{else}{ldl_score=3}{endif}④血清LDL:{=ldl_score}
{if: hdl<40}{hdl_score=2}{elseif: hdl<60}{hdl_score=1}{else}{hdl_score=0}{endif}⑤血清HDL-C:{=hdl_score}
{if: `喫煙`==no}{`喫煙_score`=0}{else}{`喫煙_score`=2}{endif}⑥喫煙:{=`喫煙_score`}
{if: age<50}{age_group="young"}{elseif: age<60}{age_group="low"}{elseif: age<70}{age_group="middle"}{else}{age_group="high"}{endif}
{score=sex_score + `喫煙_score` + bp_score + hdl_score + ldl_score + dm_score }久山町スコア:{=score}点
{if: age_group=="young" and score <13}{risk="low"}{elseif: age_group=="young" and score >12}{risk="mid"}{elseif: age_group=="low" and score <8}{risk="low"}{elseif: age_group=="low" and score >7 and score <19}{risk="mid"}{elseif: age_group=="low" and score >18 }{risk="high"}{elseif: age_group=="middle" and score <2}{risk="low"}{elseif: age_group=="middle" and score >1 and score <13}{risk="mid"}{elseif: age_group=="middle" and score >12 }{risk="high"}{elseif: age_group=="high" and score <8}{risk="mid"}{elseif: age_group=="high" and score >7 }{risk="high"}{endif}{site: text; selector=.names-name}さんは{=age}歳、{if: `虚血性心疾患/脳梗塞`==yes}二次予防になりますので厳格なコントロールが必要。LDL-Cは70未満、Non-HDL-Cは130未満、中性脂肪は150未満(空腹時)、170未満(食後)、HDL-Cは40以上が目標値になります。{elseif: `糖尿病`==yes or `慢性腎臓病`==yes or `末梢血管疾患`==yes}高リスク群です、予測される10年間の動脈硬化性疾患の発症リスクは10%以上です。LDL-Cは120未満、Non-HDL-Cは150未満、中性脂肪は150未満(空腹時)、170未満(食後)、HDL-Cは40以上が管理目標値になります{elseif: risk=="low"}久山町スコアは{=score}点、低リスク群です、予測される10年間の動脈硬化性疾患の発症リスクは2%未満です。LDL-Cは160未満、Non-HDL-Cは190未満、中性脂肪は150未満(空腹時)、170未満(食後)、HDL-Cは40以上が管理目標値になります.{elseif: risk=="mid"}久山町スコアは{=score}点、中リスク群です、予測される10年間の動脈硬化性疾患の発症リスクは2%~10%未満です。LDL-Cは140未満、Non-HDL-Cは170未満、中性脂肪は150未満(空腹時)、170未満(食後)、HDL-Cは40以上が管理目標値になります。{elseif: risk == "high"}久山町スコアは{=score}点、高リスク群です、予測される10年間の動脈硬化性疾患の発症リスクは10%以上です。LDL-Cは120未満、Non-HDL-Cは150未満、中性脂肪は150未満(空腹時)、170未満(食後)、HDL-Cは40以上が管理目標値になります{endif}

となっています。最初に{import: /imf}で電子カルテ内容を読み取ります。importコマンドで他のスニペットを再起的に利用できます。コードの詳細は下記のようになっています。

(1) スコア計算のロジック

① 性別スコア

{if: sex=="男性"}{sex_score=7}{else}{sex_score=0}{endif}

② 血圧スコア

{if: sbp<120 }{bp_score=0}
{elseif: sbp<130}{bp_score=1}
{elseif: sbp<140}{bp_score=2}
{elseif: sbp<160}{bp_score=3}
{else}{bp_score=4}
{endif}

③ LDL-C スコア

{if: ldl<120}{ldl_score=0}
{elseif: ldl<140}{ldl_score=1}
{elseif: ldl<160}{ldl_score=2}
{else}{ldl_score=3}
{endif}

④ HDL-C スコア

{if: hdl<40}{hdl_score=2}
{elseif: hdl<60}{hdl_score=1}
{else}{hdl_score=0}
{endif}

⑤ 喫煙スコア

{if: `喫煙`==no}{`喫煙_score`=0}
{else}{`喫煙_score`=2}
{endif}

⑥ 総合スコア計算

{score=sex_score + `喫煙_score` + bp_score + hdl_score + ldl_score}

5. リスク分類と診療サポート

計算されたスコアを基に、リスク分類と目標管理値を自動表示します。

{if: risk=="low"}低リスク群です。LDL-C目標値は160未満
{elseif: risk=="mid"}中リスク群です。LDL-C目標値は140未満
{elseif: risk=="high"}高リスク群です。LDL-C目標値は120未満
{endif}

さらに、冠動脈疾患や脳梗塞の既往がある場合は二次予防の目標値を設定:

{if: `冠動脈疾患`==yes or `脳血管疾患`==yes} LDL-C目標値は70未満、HDL-Cは40以上が推奨されます。

6. フローチャート

graph TD
    A[Webページから検査データ抽出開始] --> B{Webページから情報抽出};
    B -- 患者情報、既往歴、検査データ --> C[変数に格納];
    C --> D[久山町スコア計算開始];
    D --> E{性別判定};
    E -- 男性 --> F[性別スコア:7];
    E -- 女性 --> G[性別スコア:0];
    F --> H{血圧判定};
    G --> H;
    H -- sbp<120 --> I[血圧スコア:0];
    H -- 120<=sbp<130 --> J[血圧スコア:1];
    H -- 130<=sbp<140 --> K[血圧スコア:2];
    H -- 140<=sbp<160 --> L[血圧スコア:3];
    H -- sbp>=160 --> M[血圧スコア:4];
    I --> N{糖代謝異常判定};
    J --> N;
    K --> N;
    L --> N;
    M --> N;
    N -- 糖代謝異常なし --> O[糖代謝異常スコア:0];
    N -- 糖代謝異常あり --> P[糖代謝異常スコア:1];
    O --> Q{LDL-C判定};
    P --> Q;
    Q -- ldl<120 --> R[LDLスコア:0];
    Q -- 120<=ldl<140 --> S[LDLスコア:1];
    Q -- 140<=ldl<160 --> T[LDLスコア:2];
    Q -- ldl>=160 --> U[LDLスコア:3];
    R --> V{HDL-C判定};
    S --> V;
    T --> V;
    U --> V;
    V -- hdl<40 --> W[HDLスコア:2];
    V -- 40<=hdl<60 --> X[HDLスコア:1];
    V -- hdl>=60 --> Y[HDLスコア:0];
    W --> Z{喫煙判定};
    X --> Z;
    Y --> Z;
    Z -- 喫煙なし --> AA[喫煙スコア:0];
    Z -- 喫煙あり --> AB[喫煙スコア:2];
    AA --> AC[年齢判定];
    AB --> AC;
    AC -- age<50 --> AD[年齢グループ:young];
    AC -- 50<=age<60 --> AE[年齢グループ:low];
    AC -- 60<=age<70 --> AF[年齢グループ:middle];
    AC -- age>=70 --> AG[年齢グループ:high];
    AD --> AH[合計スコア計算];
    AE --> AH;
    AF --> AH;
    AG --> AH;
    AH --> AI{リスク評価};
        AI -- young, score<13 --> AJ[リスク:low];
        AI -- young, score>=13 --> AK[リスク:mid];
        AI -- low, score<8 --> AJ;
        AI -- low, 8<=score<19 --> AK;
        AI -- low, score>=19 --> AL[リスク:high];
        AI -- middle, score<2 --> AJ;
        AI -- middle, 2<=score<13 --> AK;
        AI -- middle, score>=13 --> AL;
        AI -- high, score<8 --> AK;
        AI -- high, score>=8 --> AL;

    AJ --> AM{既往歴判定};
    AK --> AM;
        AL --> AM;

    AM -- 虚血性心疾患/脳梗塞あり --> AN[二次予防目標値表示];
    AM -- 糖尿病/慢性腎臓病/末梢血管疾患あり --> AO[高リスク目標値表示];
    AM -- リスク:low --> AP[低リスク目標値表示];
    AM -- リスク:mid --> AQ[中リスク目標値表示];
    AM -- リスク:high --> AO;
    AN --> AR[結果表示];
    AO --> AR;
    AP --> AR;
    AQ --> AR;
        AR --> AS[久山町スコア計算終了];
        AS --> AT[処理終了];

7. まとめ

本システムでは、電子カルテ(クリニクス)のデータをリアルタイムで取得し、久山町スコアを自動計算することで、診療の効率化と精度向上を実現しました。

手入力不要で迅速なスコア算出
診療時のリスク評価を即時に提供
Text Blazeを活用した簡単なカスタマイズが可能

電子カルテの読み取り部分は変数などに一貫性を持たせる工夫は必要ですが他のスコア計算でも使えそうです。いろいろなITツールを利用して質の高い医療ができるように頑張ります。


*一部コードを修正しました(2025.03.05)

上記記事で、Text Blazeの {run} コマンドを使用して extractregex() で数値データを抽出する方法を紹介しました。しかし、extractregex() でデータが見つからない場合に処理が途中で停止してしまう問題が発生 することが分かりました。

この問題を回避するために、{run} を1行ずつ適用する修正 を行いました。これにより、データが欠損していてもスクリプトが途中で止まることなく、後続の処理が正しく実行されるようになりました。


問題点

例えば、以下のような {run} コマンドを使用して、複数のデータを一度に抽出しようとした場合:

{run: 
wbc=extractregex({=chart},"白血球数\s*[HL]?\s*([\d.]+)\s*/MCL")
rbc=extractregex({=chart},"赤血球数\s*[HL]?\s*([\d.]+)\s*X10000/MCL")
hgb=extractregex({=chart},"血色素量\s*[HL]?\s*([\d.]+)\s*G/DL")
hct=extractregex({=chart},"ヘマトクリット\s*[HL]?\s*([\d.]+)\s*%")
}

もし rbc のデータが chart に存在しない場合、rbc の抽出時点でスクリプトが停止し、それ以降の hgbhct の処理が実行されない という問題が発生します。


修正方法

この問題を回避するために、{run} を1行ずつ適用する方法に変更 しました。これにより、欠損値があっても処理が止まらず、すべての項目が適切に抽出されます。

修正後のコード

{run: height=extractregex({=chart},"身長:\s*([\d.]+)\s*cm")}
{run: weight=extractregex({=chart},"体重:\s*([\d.]+)\s*kg")}
{run: wbc=extractregex({=chart},"白血球数\s*[HL]?\s*([\d.]+)\s*/MCL")}
{run: rbc=extractregex({=chart},"赤血球数\s*[HL]?\s*([\d.]+)\s*X10000/MCL")}
{run: hgb=extractregex({=chart},"血色素量\s*[HL]?\s*([\d.]+)\s*G/DL")}
{run: hct=extractregex({=chart},"ヘマトクリット\s*[HL]?\s*([\d.]+)\s*%")}
{run: mcv=extractregex({=chart},"MCV\s*[HL]?\s*([\d.]+)\s*FL")}
{run: mch=extractregex({=chart},"MCH\s*[HL]?\s*([\d.]+)\s*PG")}
{run: mchc=extractregex({=chart},"MCHC\s*[HL]?\s*([\d.]+)\s*%")}
{run: plt=extractregex({=chart},"血小板数\s*[HL]?\s*([\d.]+)\s*X10000/MCL")}
{run: ast=extractregex({=chart},"AST\(GOT\)\s*[HL]?\s*([\d.]+)\s*U/L")}
{run: alt=extractregex({=chart},"ALT\(GPT\)\s*[HL]?\s*([\d.]+)\s*U/L")}
{run: ggtp=extractregex({=chart},"γ-GT\s*[HL]?\s*([\d.]+)\s*U/L")}
{run: tg=extractregex({=chart},"中性脂肪\s*[HL]?\s*([\d.]+)\s*MG/DL")}
{run: tc=extractregex({=chart},"総コレステロール\s*[HL]?\s*([\d.]+)\s*MG/DL")}
{run: hdl=extractregex({=chart},"HDLコレステロール\s*[HL]?\s*([\d.]+)\s*MG/DL")}
{run: ldl=extractregex({=chart},"LDLコレステロール\s*[HL]?\s*([\d.]+)\s*MG/DL")}
{run: glucose=extractregex({=chart},"血糖\s*[HL]?\s*([\d.]+)\s*MG/DL")}
{run: hba1c=extractregex({=chart},"HbA1c\s*NGSP\s*[HL]?\s*([\d.]+)\s*%")}

修正後の動作確認

入力 (chart の例)

身長: 165cm 
体重: 67kg
LDLコレステロール 129 MG/DL
HDLコレステロール 44 MG/DL
AST(GOT) 17 U/L
血糖 H 153 MG/DL

出力 (extractregex の結果)

height = 165
weight = 67
ldl = 129
hdl = 44
ast = 17
glucose = 153

(欠損値があってもエラーにならずスキップ)


まとめ

今回の修正により、欠損値があっても {run} コマンドが途中で停止することなく、すべてのデータを適切に抽出できるようになりました。この方法を活用することで、より安定したデータ抽出が可能になります。あまり美しくないコードなので他にスマートな方法がないかフォーラムで質問中です。

今後もText Blazeを活用して、電子カルテの入力補助や文書作成の効率化を進めていきます。

追記:Text Blaze の {run} 内で extractregex() を使用する際の新たな解決策(2025.03.05)

上記記事で、Text Blaze の {run} コマンドを使用して extractregex() を活用する方法について紹介しました。しかし、その後の検証で、欠損値(データが見つからない場合)があるとスクリプトが途中で停止する という問題が発生することが分かりました。前回の修正は {run} を1行ずつ適用する方法で回避しましたが、よりシンプルな解決策として catch() を使用する方法を採用 しました。これにより、欠損値があっても "Not found" を返し、スクリプトがエラーで停止することなく実行可能 になります。

この方法は、Text Blaze のコミュニティで教えてもらいました
詳細は、こちらのスレッドをご参照ください:
🔗 Issue with extractregex() inside {run} in Text Blaze


従来の問題点

従来のコードでは、以下のように {run} の中で extractregex() を使用してデータを抽出していました。

{run: 
wbc=extractregex({=chart},"白血球数\s*[HL]?\s*([\d.]+)\s*/MCL")
rbc=extractregex({=chart},"赤血球数\s*[HL]?\s*([\d.]+)\s*X10000/MCL")
hgb=extractregex({=chart},"血色素量\s*[HL]?\s*([\d.]+)\s*G/DL")
hct=extractregex({=chart},"ヘマトクリット\s*[HL]?\s*([\d.]+)\s*%")
ldl=extractregex({=chart},"LDLコレステロール\s*[HL]?\s*([\d.]+)\s*MG/DL")
hdl=extractregex({=chart},"HDLコレステロール\s*[HL]?\s*([\d.]+)\s*MG/DL")
}

この方法では、rbc のデータが chart 内に存在しない場合、extractregex() がエラーを返し、スクリプトの実行が停止 してしまいます。


修正方法

この問題を回避するために、catch() を使用することで extractregex() がデータを見つけられなかった場合に "" を返す ようにしました。
さらに、{run} を1つに統合し、コードの可読性を向上 させました。

修正後のコード

{run: height=catch(extractregex({=chart},"身長:\s*([\d.]+)\s*cm"), "")
weight=catch(extractregex({=chart},"体重:\s*([\d.]+)\s*kg"), "")
wbc=catch(extractregex({=chart},"白血球数\s*[HL]?\s*([\d.]+)\s*/MCL"), "")
rbc=catch(extractregex({=chart},"赤血球数\s*[HL]?\s*([\d.]+)\s*X10000/MCL"), "")
hgb=catch(extractregex({=chart},"血色素量\s*[HL]?\s*([\d.]+)\s*G/DL"), "")
hct=catch(extractregex({=chart},"ヘマトクリット\s*[HL]?\s*([\d.]+)\s*%"), "")
mcv=catch(extractregex({=chart},"MCV\s*[HL]?\s*([\d.]+)\s*FL"), "")
mch=catch(extractregex({=chart},"MCH\s*[HL]?\s*([\d.]+)\s*PG"), "")
mchc=catch(extractregex({=chart},"MCHC\s*[HL]?\s*([\d.]+)\s*%"), "")
plt=catch(extractregex({=chart},"血小板数\s*[HL]?\s*([\d.]+)\s*X10000/MCL"), "")
ast=catch(extractregex({=chart},"AST\(GOT\)\s*[HL]?\s*([\d.]+)\s*U/L"), "")
alt=catch(extractregex({=chart},"ALT\(GPT\)\s*[HL]?\s*([\d.]+)\s*U/L"), "")
ggtp=catch(extractregex({=chart},"γ-GT\s*[HL]?\s*([\d.]+)\s*U/L"), "")
ck=catch(extractregex({=chart},"CK\(CPK\)\s*[HL]?\s*([\d.]+)\s*U/L"), "")
amylase=catch(extractregex({=chart},"アミラーゼ\s*[HL]?\s*([\d.]+)\s*U/L"), "")
bilirubin=catch(extractregex({=chart},"総ビリルビン\s*[HL]?\s*([\d.]+)\s*MG/DL"), "")
tp=catch(extractregex({=chart},"総蛋白\s*[HL]?\s*([\d.]+)\s*G/DL"), "")
alb=catch(extractregex({=chart},"アルブミン\s*[HL]?\s*([\d.]+)\s*G/DL"), "")
ag_ratio=catch(extractregex({=chart},"A/G比\s*[HL]?\s*([\d.]+)"), "")
tg=catch(extractregex({=chart},"中性脂肪\s*[HL]?\s*([\d.]+)\s*MG/DL"), "")
hdl=catch(extractregex({=chart},"HDLコレステロール\s*[HL]?\s*([\d.]+)\s*MG/DL"), "")
bun=catch(extractregex({=chart},"尿素窒素\s*[HL]?\s*([\d.]+)\s*MG/DL"), "")
ua=catch(extractregex({=chart},"尿酸\s*[HL]?\s*([\d.]+)\s*MG/DL"), "")
cre=catch(extractregex({=chart},"クレアチニン\s*[HL]?\s*([\d.]+)\s*MG/DL"), "")
egfr=catch(extractregex({=chart},"eGFRcreat\s*[HL]?\s*([\d.]+)\s*ML/MIN/1.73"), "")
na=catch(extractregex({=chart},"ナトリウム\s*[HL]?\s*([\d.]+)\s*MEQ/L"), "")
k=catch(extractregex({=chart},"カリウム\s*[HL]?\s*([\d.]+)\s*MEQ/L"), "")
cl=catch(extractregex({=chart},"クロール\s*[HL]?\s*([\d.]+)\s*MEQ/L"), "")
glucose=catch(extractregex({=chart},"血糖\s*[HL]?\s*([\d.]+)\s*MG/DL"), "")
hba1c=catch(extractregex({=chart},"HbA1c\s*NGSP\s*[HL]?\s*([\d.]+)\s*%"), "")
ldl=catch(extractregex({=chart},"LDLコレステロール\s*[HL]?\s*([\d.]+)\s*MG/DL"), "")
}

改善点

catch() を使用し、extractregex() でデータが見つからなくても "" を返すように修正
{run} を1つにまとめて、よりシンプルで管理しやすいコードに
欠損データがあってもスクリプトが途中で停止せず、すべての値を取得可能


動作確認

入力 (chart の例)

身長: 165cm 
体重: 67kg
LDLコレステロール 129 MG/DL
HDLコレステロール 44 MG/DL
AST(GOT) 17 U/L
血糖 H 153 MG/DL

出力 (extractregex の結果)

height = 165
weight = 67
ldl = 129
hdl = 44
ast = 17
glucose = 153

(欠損している項目は "" になる)


まとめ

この修正により、Text Blaze の {run} コマンドを使って extractregex() でデータ抽出する際の安定性が大幅に向上 しました。
データが見つからない場合でも "" を返すことで、スクリプトの実行が止まることなく、スムーズに処理を進めることができます。いろいろな方法で同じ結果をだせるのがプログラミングの妙味ですね。

関連記事

コメント

この記事へのコメントはありません。