Skip to content

Instantly share code, notes, and snippets.

@jhyland87
Last active July 1, 2026 17:26
Show Gist options
  • Select an option

  • Save jhyland87/2836a49cb578ef34b27cd2b493e8b14b to your computer and use it in GitHub Desktop.

Select an option

Save jhyland87/2836a49cb578ef34b27cd2b493e8b14b to your computer and use it in GitHub Desktop.
Chemical Formula Parser

Matches for chemical formulas in any form I could think of.

Regex101 test

Screenshot 2026-07-01 at 9 42 58 AM Screenshot 2026-07-01 at 10 20 53 AM

Totally done by Claude. Im not nearly this good at regex

( # capture 1: the whole formula
(?![^<>]*>) # guard: don't start inside an HTML tag's attribute list
(?: # ============ HEAD — must look like a formula, not prose ============
(?: # branch A: two or more element / bracket "units"
(?:
(?:H[eogsf]?|L[iavru]|B[eahkri]?|C[arofmusenld]?|N[eiahopdb]?|O[sg]?|F[rlem]?|M[godtcn]|A[lrsgutmc]|S[icerngmb]?|P[uabotmrd]?|Kr?|T[icebmsalh]|V|Z[nr]|G[ade]|R[buhenagf]|Yb?|I[nr]?|Xe|E[urs]|D[ysb]|W|U) # any element symbol (all 118)
|[()\[\]] # ...or a bracket
)+
(?: # then any trailing subscript counts, in ANY encoding or a plain digit:
(?:
[₁₂₃₄₅₆₇₈₉][₀₁₂₃₄₅₆₇₈₉]* # subscript glyphs H₂
|[¹²³⁴⁵⁶⁷⁸⁹][⁰¹²³⁴⁵⁶⁷⁸⁹]* # superscript glyphs x²
|\\u208[1-9](?:\\u208[0-9])* # \u escape, subscript H\u2082 (unparsed JSON)
|(?:\\u00[bB][239]|\\u207[4-9])(?:\\u2070|\\u00[bB][239]|\\u207[4-9])* # \u escape, superscript
|&\#(?:0*832[1-9]|[xX]0*208[1-9]);(?:&\#(?:0*832[0-9]|[xX]0*208[0-9]);)* # HTML entity, subscript H&#8322; / H&#x2082;
|&\#(?:0*(?:178|179|185|830[89]|831[0-3])|[xX]0*(?:[bB][239]|207[4-9]));(?:&\#(?:0*(?:178|179|185|8304|830[89]|831[0-3])|[xX]0*(?:2070|[bB][239]|207[4-9]));)* # HTML entity, superscript
|<su[bp]>[1-9][0-9]*<\/su[bp]> # <sub>/<sup> tag H<sub>2</sub>
)
|[1-9][0-9]* # ...or a plain inline integer
)*
){2,}
| # branch B: a single element carrying a REQUIRED sub/superscript (e.g. "H₂")
(?:
(?:H[eogsf]?|L[iavru]|B[eahkri]?|C[arofmusenld]?|N[eiahopdb]?|O[sg]?|F[rlem]?|M[godtcn]|A[lrsgutmc]|S[icerngmb]?|P[uabotmrd]?|Kr?|T[icebmsalh]|V|Z[nr]|G[ade]|R[buhenagf]|Yb?|I[nr]?|Xe|E[urs]|D[ysb]|W|U)
|[()\[\]]
)+
(?: # required sub/superscript number (any encoding; no bare digit here)
[₁₂₃₄₅₆₇₈₉][₀₁₂₃₄₅₆₇₈₉]*|[¹²³⁴⁵⁶⁷⁸⁹][⁰¹²³⁴⁵⁶⁷⁸⁹]*|\\u208[1-9](?:\\u208[0-9])*|(?:\\u00[bB][239]|\\u207[4-9])(?:\\u2070|\\u00[bB][239]|\\u207[4-9])*|&\#(?:0*832[1-9]|[xX]0*208[1-9]);(?:&\#(?:0*832[0-9]|[xX]0*208[0-9]);)*|&\#(?:0*(?:178|179|185|830[89]|831[0-3])|[xX]0*(?:[bB][239]|207[4-9]));(?:&\#(?:0*(?:178|179|185|8304|830[89]|831[0-3])|[xX]0*(?:2070|[bB][239]|207[4-9]));)*|<su[bp]>[1-9][0-9]*<\/su[bp]>
)
)
(?:[+-](?![A-Za-z0-9]))? # optional ionic charge on the head (K+, …F₃-)
(?: # ============ zero or more salt / hydrate components ============
(?:\s*[·•‧∙⋅・・*]\s*|\.(?=[A-Za-z(\[])) # separator: a spaced dot variant, OR a tight "." right before a component
(?: # optional coefficient: a sub/sup number, an integer/fraction, or x/n
[₁₂₃₄₅₆₇₈₉][₀₁₂₃₄₅₆₇₈₉]*|[¹²³⁴⁵⁶⁷⁸⁹][⁰¹²³⁴⁵⁶⁷⁸⁹]*|\\u208[1-9](?:\\u208[0-9])*|(?:\\u00[bB][239]|\\u207[4-9])(?:\\u2070|\\u00[bB][239]|\\u207[4-9])*|&\#(?:0*832[1-9]|[xX]0*208[1-9]);(?:&\#(?:0*832[0-9]|[xX]0*208[0-9]);)*|&\#(?:0*(?:178|179|185|830[89]|831[0-3])|[xX]0*(?:[bB][239]|207[4-9]));(?:&\#(?:0*(?:178|179|185|8304|830[89]|831[0-3])|[xX]0*(?:2070|[bB][239]|207[4-9]));)*|<su[bp]>[1-9][0-9]*<\/su[bp]>|[1-9][0-9]*(?:\/[1-9][0-9]*)?|[xn]
)?
(?: # the component's own units (elements/brackets + subscripts), one or more
(?:
(?:H[eogsf]?|L[iavru]|B[eahkri]?|C[arofmusenld]?|N[eiahopdb]?|O[sg]?|F[rlem]?|M[godtcn]|A[lrsgutmc]|S[icerngmb]?|P[uabotmrd]?|Kr?|T[icebmsalh]|V|Z[nr]|G[ade]|R[buhenagf]|Yb?|I[nr]?|Xe|E[urs]|D[ysb]|W|U)
|[()\[\]]
)+
(?:
(?:[₁₂₃₄₅₆₇₈₉][₀₁₂₃₄₅₆₇₈₉]*|[¹²³⁴⁵⁶⁷⁸⁹][⁰¹²³⁴⁵⁶⁷⁸⁹]*|\\u208[1-9](?:\\u208[0-9])*|(?:\\u00[bB][239]|\\u207[4-9])(?:\\u2070|\\u00[bB][239]|\\u207[4-9])*|&\#(?:0*832[1-9]|[xX]0*208[1-9]);(?:&\#(?:0*832[0-9]|[xX]0*208[0-9]);)*|&\#(?:0*(?:178|179|185|830[89]|831[0-3])|[xX]0*(?:[bB][239]|207[4-9]));(?:&\#(?:0*(?:178|179|185|8304|830[89]|831[0-3])|[xX]0*(?:2070|[bB][239]|207[4-9]));)*|<su[bp]>[1-9][0-9]*<\/su[bp]>)|[1-9][0-9]*
)*
)+
(?:[+-](?![A-Za-z0-9]))? # optional charge on the component
)*
)
/**
* https://regex101.com/r/h3ZnXX/4
*/
/**
* Map of ASCII digits to their Unicode subscript characters (U+2080–U+2089).
*/
export const SUBSCRIPTS: { [key: string]: string } = {
"0": "\u2080",
"1": "\u2081",
"2": "\u2082",
"3": "\u2083",
"4": "\u2084",
"5": "\u2085",
"6": "\u2086",
"7": "\u2087",
"8": "\u2088",
"9": "\u2089",
} as const;
/**
* Map of ASCII digits to their Unicode superscript characters. Note these are
* NOT contiguous: ¹²³ live in Latin-1 (U+00B9/B2/B3), the rest in the
* "Superscripts and Subscripts" block.
*/
export const SUPERSCRIPTS: { [key: string]: string } = {
"0": "\u2070",
"1": "\u00B9",
"2": "\u00B2",
"3": "\u00B3",
"4": "\u2074",
"5": "\u2075",
"6": "\u2076",
"7": "\u2077",
"8": "\u2078",
"9": "\u2079",
} as const;
export const SUBSCRIPT_GLYPHS: { [key: string]: string } = {
/* eslint-disable */
/* tslint:disable */
"0": "₀",
"1": "₁",
"2": "₂",
"3": "₃",
"4": "₄",
"5": "₅",
"6": "₆",
"7": "₇",
"8": "₈",
"9": "₉",
/* eslint-enable */
/* tslint:enable */
} as const;
export const SUPERSCRIPT_GLYPHS: { [key: string]: string } = {
/* eslint-disable */
/* tslint:disable */
"0": "⁰",
"1": "¹",
"2": "²",
"3": "³",
"4": "⁴",
"5": "⁵",
"6": "⁶",
"7": "⁷",
"8": "⁸",
"9": "⁹",
/* eslint-enable */
/* tslint:enable */
} as const;
export const subscript = (str: string) => {
return str.replace(/[0-9]/g, (match) => SUBSCRIPT_GLYPHS[match] || match);
};
/**
* Converts regular numbers in a string to superscript Unicode characters.
* @param str - The string containing numbers to convert to superscripts
* @returns The string with numbers converted to superscript characters
* @example
* ```typescript
* superscript("10^2") // Returns "10²"
* superscript("2^3") // Returns "2³"
* ```
* @source
*/
export const superscript = (str: string) => {
return str.replace(/[0-9]/g, (match) => SUPERSCRIPT_GLYPHS[match] || match);
};
export const superscriptGlyph = (str: string) => {
for (const key in SUPERSCRIPT_GLYPHS) {
str = str.replace(new RegExp(SUPERSCRIPTS[key], "g"), SUPERSCRIPT_GLYPHS[key]);
}
return str;
};
export const subscriptGlyph = (str: string) => {
for (const key in SUBSCRIPT_GLYPHS) {
str = str.replace(new RegExp(SUBSCRIPTS[key], "g"), SUBSCRIPT_GLYPHS[key]);
}
return str;
};
/**
* Finds the first chemical-formula-like substring in `text` and returns it, or
* `undefined` if none is found.
*
* Recognizes sub/superscript numbers written in any of four representations,
* so it works on raw scraped text regardless of how the source encoded them:
* • literal glyphs H₂O / x²
* • \u escape text H\u2082O (e.g. unparsed JSON)
* • HTML entities H&#8322;O / H&#x2082;O (decimal or hex)
* • <sub>/<sup> tags H<sub>2</sub>O
*
* Also handles salts/hydrates (·, •, *, or a tight ".") with optional integer,
* fraction, or variable (x/n) coefficients, and trailing ionic charge signs.
*/
export const findFormulaInText = (text: string): string | undefined => {
// Valid element symbols (all 118). Gates the match so prose isn't read as a formula.
const element =
"(?:H[eogsf]?|L[iavru]|B[eahkri]?|C[arofmusenld]?|N[eiahopdb]?|O[sg]?|F[rlem]?|M[godtcn]|A[lrsgutmc]|S[icerngmb]?|P[uabotmrd]?|Kr?|T[icebmsalh]|V|Z[nr]|G[ade]|R[buhenagf]|Yb?|I[nr]?|Xe|E[urs]|D[ysb]|W|U)";
// A sub/superscript "number" (no leading zero), in each accepted representation.
// Characters are enumerated rather than ranged so engines that don't compute
// Unicode ranges (byte-oriented / non-Unicode modes) still match them.
const glyphSub = "[₁₂₃₄₅₆₇₈₉][₀₁₂₃₄₅₆₇₈₉]*";
const glyphSup = "[¹²³⁴⁵⁶⁷⁸⁹][⁰¹²³⁴⁵⁶⁷⁸⁹]*";
// \u escape text (literal backslash-u-XXXX, e.g. before JSON.parse).
const escSub = String.raw`\\u208[1-9](?:\\u208[0-9])*`;
const escSup = String.raw`(?:\\u00[bB][239]|\\u207[4-9])(?:\\u2070|\\u00[bB][239]|\\u207[4-9])*`;
// HTML numeric entities, decimal or hex, with optional leading zeros.
const entSub = "&#(?:0*832[1-9]|[xX]0*208[1-9]);(?:&#(?:0*832[0-9]|[xX]0*208[0-9]);)*";
const entSup =
"&#(?:0*(?:178|179|185|830[89]|831[0-3])|[xX]0*(?:[bB][239]|207[4-9]));(?:&#(?:0*(?:178|179|185|8304|830[89]|831[0-3])|[xX]0*(?:2070|[bB][239]|207[4-9]));)*";
// <sub>2</sub> / <sup>2</sup> tags.
const tag = "<su[bp]>[1-9][0-9]*</su[bp]>";
const subSup = `(?:${glyphSub}|${glyphSup}|${escSub}|${escSup}|${entSub}|${entSup}|${tag})`;
// The looser "sub/sup or inline digit" count used inside a unit.
const subPart = `(?:${subSup}|[1-9][0-9]*)`;
// One "unit": a run of elements/brackets, then any trailing subscripts.
const unit = `(?:(?:${element}|[()\\[\\]])+(?:${subPart})*)`;
// The head must look like a formula and not prose: either ≥2 element/bracket units, or a single
// element carrying a subscript/superscript (e.g. "H₂"). A lone bare element, or a single element
// with only an inline digit (e.g. "B12" in prose), is intentionally not enough.
const head = `(?:(?:${unit}){2,}|(?:${element}|[()\\[\\]])+${subSup})`;
// An optional ionic charge sign. The lookahead (not followed by a letter/digit) keeps it from
// grabbing an ordinary hyphen inside a word like "CO-op", while still allowing "K+", "…F₃-.K+".
const charge = "(?:[+-](?![A-Za-z0-9]))?";
// Salt/hydrate separator: a spaced dot ("·"/"•"/"‧"/"∙"/"⋅"/"・"/"・"/"*"), OR a tight "." that is
// immediately followed by a component (so it ignores sentence periods and decimal points). The
// several dot code points cover the visually identical characters different data sources emit.
const separator = "(?:\\s*[·•‧∙⋅・・*]\\s*|\\.(?=[A-Za-z(\\[]))";
// A leading coefficient after a separator: a sub/sup number, an integer or fraction (e.g. "12",
// "1/2"), or a variable hydrate count (x/n).
const coefficient = `(?:${subSup}|[1-9][0-9]*(?:/[1-9][0-9]*)?|[xn])`;
// The whole formula: the head (+optional charge), then any number of
// "separator coefficient? units (+optional charge)" salt/hydrate components.
const pattern = new RegExp(
`((?![^<>]*>)${head}${charge}(?:${separator}(?:${coefficient})?${unit}+${charge})*)`,
);
const match = text.match(pattern);
if (!match) {
return;
}
return match[0]
.replace(/<sub>(\d+)<\/sub>/g, (_match, p1) => subscriptGlyph(p1 || ""))
.replace(/<sup>(\d+)<\/sup>/g, (_match, p1) => superscriptGlyph(p1 || ""))
.replace(
/(?:\\u208[0-9](?:\\u208[0-9])*|(?:\\u00[bB][239]|\\u207[4-9])(?:\\u2070|\\u00[bB][239]|\\u207[4-9]))/g,
(match) => subscriptGlyph(match),
);
};
const textStrings = [
"example: C₃₃H₂₅N₃O₁₂S • ₄K",
"C₂₄H₂₀KN₅O₅S",
"KBr",
"C₁₆H₃₃KO₂",
"Here is a chemical formula: C₁₀H₇KN₆O·xH₂O",
"C₃₆H₂₅Cl₂N₂O₁₃ • ₅K",
"C₂₀H₂₀FN₆O₅·K",
"C₂₈H₁₈F₂N₃O₁₄ • ₅K",
"C₂₃H₂₈ClN₃O₅S • K",
"C₂₆H₃₄NO₄ • K",
"KN(C(O)CH₂)₂",
"C₂H₃KOS",
"C₁₅H₁₂N₅O₄ • K",
"C₄H₈N₃O₅P • ₂K",
"CHBF₅-.K+",
"C₆H₁₂O₁₅P₃ • ₃K",
"C₃H₂N₂O₃.K",
"C₄H₂NO₂SCl.K",
"C₈H₁₃BO₂F₃-.K+",
"C₉H₁₃O₄*K",
"C₁₁H₁₃BOF₃-.K+",
"C₄H₅BF₅-.K+",
"C₁₂H₁₆BNO₂F₃S-.K+",
"C₈H₁₆BNO₂F₃-.K+",
"C₉H₁₆BNO₂F₃-.K+",
"AlK(SO₄)₂·12H₂O",
"CrKO₈S₂·12H₂O",
"C₁₈H₃₅O₂·K",
"C₁₁H₁₈KNO₁₀S₂",
"C₈K",
"C₂₉H₂₂K₅N₃O₁₄",
"C₁₇H₃₂KNO₁₀S₃",
"C₁₇H₁₈KN₃O₃S",
"C₁₂H₁₀BiK₃O₁₄",
"C₁₅H₂₀NO₉S₂K",
"C₁₂H₈BiK₅O₁₄",
"C₈H₁₅KO₂",
"C₁₉H₂₃N₃O₃",
"C₃₀H₂₃KN₄O₈",
"C₄₂H₆₁KO₁₆",
"C₆H₉KO₃",
"C₆H₄BBrF₃K",
"C₆H₃K₂NO₇S",
"CF₃KO₂S",
"H₁₄K₃O₁₁P",
"C₁₀H₇KO₆S",
"C₂H₅BF₃OK",
"C₁₈H₂₉KO₃S",
"C₃H₅BF₃K",
"C₆H₁₂O₁₅P₃ • ₃K",
"C₃H₂N₂O₃.K",
"C₄H₂NO₂SCl.K",
"C₈H₁₃BO₂F₃-.K+",
"C₉H₁₃O₄*K",
"C₁₁H₁₃BOF₃-.K+",
"C₄H₅BF₅-.K+",
"C₁₂H₁₆BNO₂F₃S-.K+",
"C₈H₁₆BNO₂F₃-.K+",
"C₉H₁₆BNO₂F₃-.K+",
"AlK(SO₄)₂·12H₂O",
"CrKO₈S₂·12H₂O",
"C₁₈H₃₅O₂·K",
"C₁₆H₁₆K₃O₇PS",
"C₃H₆KN₃S",
"C₁₁H₁₈BF₃KNO₂",
"K₂SO₄",
"KHI₂O₆",
"K₃PO₄",
"K\u2083O",
"K₂HPO₄·3H₂O",
"K₂HPO₄",
"K₂CO₃·3/2H₂O",
"C₄K₂O₉Ti·2H₂O",
"K₂C₂O₄·H₂O",
"C₆H₁₁KO₇",
"K₂S₂O₈",
"C₈H₄K₂O₁₂Sb₂·3H₂O",
"C₄H₄O₆K₂·1/2H₂O",
"C<sub>33</sub>H<sub>25</sub>N<sub>3</sub>O<sub>12</sub>S • <sub>4</sub>K",
"C<sub>24</sub>H<sub>20</sub>KN<sub>5</sub>O<sub>5</sub>S",
"C<sub>10</sub>H<sub>7</sub>KN<sub>6</sub>O·xH<sub>2</sub>O",
"KBr",
"C<sub>36</sub>H<sub>25</sub>Cl<sub>2</sub>N<sub>2</sub>O<sub>13</sub> • <sub>5</sub>K",
"C<sub>20</sub>H<sub>20</sub>FN<sub>6</sub>O<sub>5</sub>·K",
"C<sub>28</sub>H<sub>18</sub>F<sub>2</sub>N<sub>3</sub>O<sub>14</sub> • <sub>5</sub>K",
"C<sub>16</sub>H<sub>33</sub>KO<sub>2</sub>",
"C<sub>23</sub>H<sub>28</sub>ClN<sub>3</sub>O<sub>5</sub>S • K",
"C<sub>26</sub>H<sub>34</sub>NO<sub>4</sub> • K",
"KN(C(O)CH<sub>2</sub>)<sub>2</sub>",
"C<sub>2</sub>H<sub>3</sub>KOS",
"C<sub>15</sub>H<sub>12</sub>N<sub>5</sub>O<sub>4</sub> • K",
"C<sub>11</sub>H<sub>18</sub>KNO<sub>10</sub>S<sub>2</sub>",
"C<sub>8</sub>K",
"C<sub>29</sub>H<sub>22</sub>K<sub>5</sub>N<sub>3</sub>O<sub>14</sub>",
"C<sub>17</sub>H<sub>32</sub>KNO<sub>10</sub>S<sub>3</sub>",
"C<sub>17</sub>H<sub>18</sub>KN<sub>3</sub>O<sub>3</sub>S",
"C<sub>32</sub>H<sub>26</sub>K<sub>5</sub>N<sub>3</sub>O<sub>12</sub>",
"C<sub>11</sub>H<sub>18</sub>KNO<sub>10</sub>S<sub>2</sub>",
"C<sub>14</sub>H<sub>26</sub>KNO<sub>10</sub>S<sub>3</sub>",
"C<sub>16</sub>H<sub>30</sub>KNO<sub>10</sub>S<sub>3</sub>",
"C<sub>20</sub>H<sub>28</sub>KNO<sub>14</sub>S<sub>2</sub>",
"C<sub>18</sub>H<sub>34</sub>KNO<sub>10</sub>S<sub>3</sub>",
"C<sub>12</sub>H<sub>10</sub>BiK<sub>3</sub>O<sub>14</sub>",
"C<sub>15</sub>H<sub>20</sub>NO<sub>9</sub>S<sub>2</sub>K",
"C<sub>12</sub>H<sub>8</sub>BiK<sub>5</sub>O<sub>14</sub>",
"C<sub>8</sub>H<sub>15</sub>KO<sub>2</sub>",
"C<sub>4</sub>H<sub>8</sub>N<sub>3</sub>O<sub>5</sub>P • <sub>2</sub>K",
"C<sub>19</sub>H<sub>23</sub>N<sub>3</sub>O<sub>3</sub>",
"C<sub>30</sub>H<sub>23</sub>KN<sub>4</sub>O<sub>8</sub>",
"C<sub>42</sub>H<sub>61</sub>KO<sub>16</sub>",
"C<sub>6</sub>H<sub>9</sub>KO<sub>3</sub>",
"C<sub>6</sub>H<sub>4</sub>BBrF<sub>3</sub>K",
"C<sub>6</sub>H<sub>3</sub>K<sub>2</sub>NO<sub>7</sub>S",
"CF<sub>3</sub>KO<sub>2</sub>S",
"H<sub>14</sub>K<sub>3</sub>O<sub>11</sub>P",
"C<sub>10</sub>H<sub>7</sub>KO<sub>6</sub>S",
"C<sub>2</sub>H<sub>5</sub>BF<sub>3</sub>OK",
"C<sub>6</sub>H<sub>11</sub>OS<sub>2</sub>K",
"CHBF<sub>5</sub>-.K+",
"C<sub>9</sub>H<sub>11</sub>BF<sub>3</sub>K",
"C<sub>18</sub>H<sub>29</sub>KO<sub>3</sub>S",
"C<sub>3</sub>H<sub>5</sub>BF<sub>3</sub>K",
"C<sub>6</sub>H<sub>12</sub>O<sub>15</sub>P<sub>3</sub> • <sub>3</sub>K",
"C<sub>3</sub>H<sub>2</sub>N<sub>2</sub>O<sub>3</sub>.K",
"C<sub>4</sub>H<sub>2</sub>NO<sub>2</sub>SCl.K",
"C<sub>8</sub>H<sub>13</sub>BO<sub>2</sub>F<sub>3</sub>-.K+",
"C<sub>9</sub>H<sub>13</sub>O<sub>4</sub>*K",
"C<sub>11</sub>H<sub>13</sub>BOF<sub>3</sub>-.K+",
"C<sub>4</sub>H<sub>5</sub>BF<sub>5</sub>-.K+",
"C<sub>4</sub>H<sub>4</sub>KN<sub>3</sub>O<sub>4</sub>S<sub>2</sub>",
"C<sub>12</sub>H<sub>16</sub>BNO<sub>2</sub>F<sub>3</sub>S-.K+",
"C<sub>8</sub>H<sub>16</sub>BNO<sub>2</sub>F<sub>3</sub>-.K+",
"C<sub>3</sub>H<sub>6</sub>KN<sub>3</sub>S",
"C<sub>9</sub>H<sub>16</sub>BNO<sub>2</sub>F<sub>3</sub>-.K+",
"C<sub>16</sub>H<sub>16</sub>K<sub>3</sub>O<sub>7</sub>PS",
"C<sub>11</sub>H<sub>18</sub>BF<sub>3</sub>KNO<sub>2</sub>",
"K<sub>2</sub>SO<sub>4</sub>",
"AlK(SO<sub>4</sub>)<sub>2</sub>·12H<sub>2</sub>O",
"CrKO<sub>8</sub>S<sub>2</sub>·12H<sub>2</sub>O",
"C<sub>18</sub>H<sub>35</sub>O<sub>2</sub>·K",
"KHI<sub>2</sub>O<sub>6</sub>",
"KIO<sub>3</sub>",
"KHCO<sub>3</sub>",
"K<sub>3</sub>PO<sub>4</sub>",
"K<sub>2</sub>HPO<sub>4</sub>·3H<sub>2</sub>O",
"K<sub>2</sub>HPO<sub>4</sub>",
"K<sub>2</sub>CO<sub>3</sub>·3/2H<sub>2</sub>O",
"C<sub>7</sub>H<sub>5</sub>KO<sub>2</sub>",
"KHC<sub>2</sub>O<sub>4</sub>",
"C<sub>4</sub>K<sub>2</sub>O<sub>9</sub>Ti·2H<sub>2</sub>O",
"K<sub>2</sub>C<sub>2</sub>O<sub>4</sub>·H<sub>2</sub>O",
"C<sub>6</sub>H<sub>11</sub>KO<sub>7</sub>",
"K<sub>2</sub>S<sub>2</sub>O<sub>8</sub>",
"C<sub>4</sub>H<sub>5</sub>KO<sub>6</sub>",
"C<sub>8</sub>H<sub>4</sub>K<sub>2</sub>O<sub>12</sub>Sb<sub>2</sub>·3H<sub>2</sub>O",
"C<sub>4</sub>H<sub>4</sub>O<sub>6</sub>K<sub>2</sub>·1/2H<sub>2</sub>O",
];
function Result(text, formula) {
this.text = text;
this.formula = formula;
}
const results: (typeof Result)[] = textStrings.map(
(text) => new Result(text, findFormulaInText(text)),
);
console.table(results);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment