/* Prescription.cs * part of zaaReloaded2 * * Copyright 2015-2017 Daniel Kraus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; namespace zaaReloaded2.Medication { /// /// Represents a prescription /// public class Prescription { #region Static methods /// /// Determines whether a line contains prescriptions. /// /// Line to inspect. /// True if the line contains prescriptions. public static bool IsCanonicalPrescriptionLine(string line) { return canonicalRegex.IsMatch(line); } /// /// Determines if a line contains prescriptions, either canonical /// ones or alternative ones (in the form "Ramipril 5 mg \t alle 2 Tage"). /// /// Line to examine. /// True if the line potentially contains prescriptions. public static bool IsPotentialPrescriptionLine(string line) { return unifiedRegex.IsMatch(line); } #endregion #region Factory /// /// Creates a new Prescription object by parsing a line (e.g., /// from a physician's letter). /// /// Line to parse /// Prescription created from the public static Prescription FromLine(string line) { // Replace any runs of whitespace with a single space // (from http://stackoverflow.com/a/206946/270712) // line = Regex.Replace(line, @"\s+", " "); Match m = unifiedRegex.Match(line); int n = m.Groups[DOSE_GROUP].Captures.Count; return new Prescription( spaceRegex.Replace(m.Groups["drug"].Value, " "), n > 0 ? m.Groups[DOSE_GROUP].Captures[0].Value : String.Empty, n > 1 ? m.Groups[DOSE_GROUP].Captures[1].Value : String.Empty, n > 2 ? m.Groups[DOSE_GROUP].Captures[2].Value : String.Empty, n > 3 ? m.Groups[DOSE_GROUP].Captures[3].Value : String.Empty, m.Groups["comment"].Value ); } /// /// Extracts several prescriptions from a given line. /// /// Line that contains several prescriptions. /// Enumerable with s. public static IList ManyFromLine(string line) { // line = Regex.Replace(line, @"\s+", " "); MatchCollection mc = unifiedRegex.Matches(line); List list = new List(); foreach (Match m in mc) { int n = m.Groups[DOSE_GROUP].Captures.Count; list.Add(new Prescription( spaceRegex.Replace(m.Groups["drug"].Value, " "), n > 0 ? m.Groups[DOSE_GROUP].Captures[0].Value : String.Empty, n > 1 ? m.Groups[DOSE_GROUP].Captures[1].Value : String.Empty, n > 2 ? m.Groups[DOSE_GROUP].Captures[2].Value : String.Empty, n > 3 ? m.Groups[DOSE_GROUP].Captures[3].Value : String.Empty, m.Groups["comment"].Value ) ); } return list; } #endregion #region Properties public string Drug { get; set; } public string Morning { get; set; } public string Noon { get; set; } public string Evening { get; set; } public string Night { get; set; } public string Comment { get; set; } /// /// Determines whether the drug is MMF or a derivative. /// public bool IsMmf { get { string d = Drug.ToLower(); return d.StartsWith("mmf") || d.StartsWith("cellcept") || d.StartsWith("cell cept") || d.StartsWith("myfortic") || d.StartsWith("mycophenol"); } } #endregion #region Overrides public override string ToString() { string s = Drug + "\t"; if (!String.IsNullOrEmpty(Morning)) { s += Morning; } else { if (!(String.IsNullOrEmpty(Noon) && String.IsNullOrEmpty(Evening) && String.IsNullOrEmpty(Night))) { s += "0"; } } if (!String.IsNullOrEmpty(Noon)) { s += "-" + Noon; } else { if (!(String.IsNullOrEmpty(Evening) && String.IsNullOrEmpty(Night))) { s += "-0"; } } if (!String.IsNullOrEmpty(Evening)) { s += "-" + Evening; } else { if (!String.IsNullOrEmpty(Night)) { s += "-0"; } } if (!String.IsNullOrEmpty(Night)) { s += "-" + Night; } if (!String.IsNullOrEmpty(Comment)) { if (!s.EndsWith("\t")) { s += " "; } s += Comment; } return s; } #endregion #region Constructors public Prescription() { } public Prescription(string drug) : this() { Drug = drug.Trim(); } public Prescription(string drug, string morning, string noon, string evening, string night) : this(drug) { Morning = morning.Trim(); Noon = noon.Trim(); Evening = evening.Trim(); Night = night.Trim(); } public Prescription(string drug, string morning, string noon, string evening, string night, string comment) : this(drug, morning, noon, evening, night) { Comment = comment.Trim(); } #endregion #region Fields private const string DOSE_GROUP = "dose"; private const string DOSE = @"(\d\s+1/[234]|(\d\s?)?[\u00bd\u2153\u00bc]|\d+)"; private const string SPACER = @"(\s*[-\u2012\u2013\u2014]+\s*)"; /// /// The 'canonical' regex matches a prescription the form "Ramipril 5 mg 1-0-0" /// with or without trailing comment. /// /// /// Enclose entire regular expression in parentheses so we can use it /// with or without trailing comment. /// private const string canonicalPattern = @"((?[^\t]+)\s+" + @"(?" + DOSE + @")" + SPACER + @"(?" + DOSE + @")" + SPACER + @"(?" + DOSE + @")" + @"(" + SPACER + @"(?" + DOSE + @"))?" + @"( +(?[^\t]+))?\s*)"; private static readonly Regex canonicalRegex = new Regex(canonicalPattern); /// /// The 'alternative' regex matches prescriptions that do not contain regular /// dosing intervals ("1-0-0"), but free-style comments: "Cotrim forte alle 2 Tage". /// /// /// Because this alternative pattern matches other lines as well (e.g. with /// signature names), it requires special handling. /// private const string alternativePattern = @"((?[^\t]+)( +|\t+)(?[^\t]+))"; private static readonly Regex alternativeRegex = new Regex(alternativePattern); private static readonly Regex unifiedRegex = new Regex( "(" + canonicalPattern + "|" + alternativePattern + ")"); /// /// A 'cached', reusable regex to match several whitespace characters. /// private static readonly Regex spaceRegex = new Regex(@"\s+"); #endregion } }