ChemPal Documentation - v1.6.0
    Preparing search index...
    • Extracts a solution concentration from a ScienceLab product title.

      Handles the forms the catalog uses, in order of precedence: molarity (0.7 Molar) and normality (0.100 Normal) — the earliest-stated of the two wins when both appear — then mass concentration (800 ppm), then a percentage (70% (v/v), 20% w/v, 90+%, >95%), then g/L, then a bare stabilizer marker ((w/BHT)). Molarity/normality/ppm deliberately outrank a percentage, because a percentage stated alongside them describes the solvent or matrix (1000 ppm … in 3% HNO₃, 0.1 Normal in 90% Isopropanol), not the product. A v/v, w/v, or w/w method marker is appended to a percentage or ppm value.

      Parameters

      • title: string

        The product title.

      Returns undefined | string

      The concentration string, or undefined when the title states none.

      parseConcentration('Isopropyl Alcohol 70% (v/v) Aqueous Solution'); // "70% (v/v)"
      parseConcentration('Nitric Acid 6.0 Normal Aqueous Solution'); // "6.0 Normal"
      parseConcentration('Bromide Standard (w/w) 800 PPM as Br'); // "800 ppm (w/w)"
      parseConcentration('Sodium Chloride, ACS Grade'); // undefined
      export function parseConcentration(title: string): string | undefined {
      if (typeof title !== 'string' || title.length === 0) {
      return undefined;
      }
      const text = title.replace(/&gt;/gi, '>').replace(/&lt;/gi, '<').replace(/&ge;/gi, '≥');
      const method = normalizeMethod(text.match(CONCENTRATION_METHOD)?.[0]);
      const withMethod = (core: string) => (method ? `${core} ${method}` : core);

      // Molarity / normality outrank a percentage (a co-occurring percent is the
      // solvent). Between the two, the earliest-stated wins.
      const molar = text.match(/(\d+(?:\.\d+)?)\s*Molar\b/i);
      const normal = text.match(/(\d+(?:\.\d+)?)\s*Normal\b/i);
      if (molar && (!normal || (molar.index ?? 0) <= (normal.index ?? 0))) {
      return `${molar[1]} Molar`;
      }
      if (normal) {
      return `${normal[1]} Normal`;
      }

      const ppm = text.match(/(\d[\d,]*(?:\.\d+)?)\s*ppm\b/i);
      if (ppm) {
      return withMethod(`${ppm[1]} ppm`);
      }

      // Comparator (`>`/`≥`), number, optional range/`+`, then `%`.
      const percent = text.match(/([<>≥≤]\s*)?\d+(?:\.\d+)?(?:\s*[-–]\s*\d+(?:\.\d+)?)?\s*\+?\s*%\+?/);
      if (percent) {
      return withMethod(percent[0].replace(/\s+/g, ''));
      }

      const gramsPerLiter = text.match(/(\d+(?:\.\d+)?)\s*g\/L\b/i);
      if (gramsPerLiter) {
      return withMethod(`${gramsPerLiter[1]} g/L`);
      }

      // A stabilizer marker with no numeric concentration, e.g. "(w/BHT)".
      return method;
      }