Matches for chemical formulas in any form I could think of.
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₂ / H₂ | |
| |&\#(?: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₂O / H₂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); |