feat: Alpha-ID-SE corpus parser with code normalization
This commit is contained in:
+43
-1
@@ -1 +1,43 @@
|
|||||||
// implemented in a later task
|
use crate::model::{AlphaIdEntry, AppError};
|
||||||
|
|
||||||
|
/// Normalize an ICD code field by removing classification marks.
|
||||||
|
pub fn normalize_code(raw: &str) -> String {
|
||||||
|
raw.trim().trim_end_matches(['+', '*', '!']).trim().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_line(line: &str) -> Option<AlphaIdEntry> {
|
||||||
|
let f: Vec<&str> = line.split('|').collect();
|
||||||
|
if f.len() < 8 { return None; }
|
||||||
|
Some(AlphaIdEntry {
|
||||||
|
valid: f[0].trim() == "1",
|
||||||
|
alpha_id: f[1].trim().to_string(),
|
||||||
|
icd_primary: normalize_code(f[2]),
|
||||||
|
icd_star: normalize_code(f[3]),
|
||||||
|
icd_addon: normalize_code(f[4]),
|
||||||
|
icd_primary2: normalize_code(f[5]),
|
||||||
|
orpha: f[6].trim().to_string(),
|
||||||
|
text: f[7].trim().to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(path: &str) -> Result<Vec<AlphaIdEntry>, AppError> {
|
||||||
|
let raw = std::fs::read_to_string(path)
|
||||||
|
.map_err(|e| AppError::Io(format!("{path}: {e}")))?;
|
||||||
|
let entries: Vec<AlphaIdEntry> = raw
|
||||||
|
.lines()
|
||||||
|
.filter(|l| !l.trim().is_empty())
|
||||||
|
.filter_map(parse_line)
|
||||||
|
.collect();
|
||||||
|
if entries.is_empty() {
|
||||||
|
return Err(AppError::Parse(format!("no entries parsed from {path}")));
|
||||||
|
}
|
||||||
|
Ok(entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The primary ICD code a matched entry contributes (falls back to star/addon).
|
||||||
|
pub fn primary_code(e: &AlphaIdEntry) -> Option<&str> {
|
||||||
|
for c in [&e.icd_primary, &e.icd_primary2, &e.icd_star, &e.icd_addon] {
|
||||||
|
if !c.is_empty() { return Some(c); }
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
use alpha_id::corpus;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_pipe_line_into_entry() {
|
||||||
|
let line = "1|I69812|A01.0+|I39.8*|||99745|Typhus-Endokarditis";
|
||||||
|
let e = corpus::parse_line(line).expect("should parse");
|
||||||
|
assert_eq!(e.alpha_id, "I69812");
|
||||||
|
assert!(e.valid);
|
||||||
|
assert_eq!(e.icd_primary, "A01.0"); // normalized: no '+'
|
||||||
|
assert_eq!(e.icd_star, "I39.8"); // normalized: no '*'
|
||||||
|
assert_eq!(e.orpha, "99745");
|
||||||
|
assert_eq!(e.text, "Typhus-Endokarditis");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalid_flag_is_false() {
|
||||||
|
let line = "0|I97837|||U81!|||Bakterien mit Multiresistenz";
|
||||||
|
let e = corpus::parse_line(line).unwrap();
|
||||||
|
assert!(!e.valid);
|
||||||
|
assert_eq!(e.icd_addon, "U81"); // field 5, '!' stripped
|
||||||
|
assert_eq!(e.icd_primary, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn loads_full_real_corpus() {
|
||||||
|
let entries = corpus::load("data/icd10gm2026_alphaidse_edvtxt_20250926.txt").unwrap();
|
||||||
|
assert_eq!(entries.len(), 90_898);
|
||||||
|
assert!(entries.iter().any(|e| e.text.contains("Diabetes mellitus Typ 2")));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user