UNPKG

@gerhobbelt/mathjax-third-party-extensions

Version:

A list of MathJax extensions provided by third-party contributors

200 lines (180 loc) 6.92 kB
/************************************************************* * * MathJax/extensions/TeX/siunitx/number-parser-regex.js * * Parses numbers approximating LaTeX's siunitx number parser * * --------------------------------------------------------------------- * * Copyright (c) 2016 Yves Delley, https://github.com/burnpanck * * 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. */ /* eslint-env amd */ define(['./siunitx-options-definition'],function(SIunitxOptions) { 'use strict'; var exports = {}; var TEX = MathJax.InputJax.TeX; var SINumberParser = exports.SINumberParser = MathJax.Object.Subclass({ Init: function (string, options, env) { this.string = string; this.i = 0; if (options === undefined) options = SIunitxOptions(); else if (!(options instanceof SIunitxOptions)) { console.log(options,SIunitxOptions); throw "SINumberParser expects an options object"; } this.options = options; this.regex = this.GenerateRegex(options); this.Parse(); }, GenerateRegex: function (options) { function reescape(s) { return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); } var decimal_sep = '(?:\\.|,)'; var sign = '(\\+|-|\\\\pm|\\\\mp|\\\\le|\\\\leq|\\\\ll|\\\\ge|\\\\geq|\\\\gg|\\\\sim)'; var digit = '[0-9]'; var complex_root = '(?:i|j)'; var exponent = '(?:[eEdD](-?\\d+))'; var product = reescape(this.options['input-product']); var quotient = reescape(this.options['input-quotient']); var decimal_number = '(' + digit + '*)(?:' + decimal_sep + '(' + digit + '*))?'; // 2 grps var imaginary_number = '(?:' + decimal_number + complex_root + '|' + complex_root + decimal_number + ')'; // 2 + 2 = 4 grps var complex_number = sign + '?' + decimal_number + '(?:' + sign + imaginary_number + ')?'; // 1 + 2 + 1 + 4 = 8 grps var full_number = complex_number + exponent + '?'; // 8+1= 9 grps var multipart = '(' + product + '|' + quotient + ')'; // 1 grp var multi_part_number = full_number + '(?:' + multipart + '(' + full_number + '(?:' + multipart + full_number + ')*))?'; // 9+1+1+9+1+9 = 30 grps // console.log(full_number); var ret = new RegExp('^' + multi_part_number + '$'); return ret }, Parse: function () { var str = this.string.replace(/\s+/gi, ''); var replacements = { '+-': '\\pm', '-+': '\\mp', '<=': '\\leq', '>=': '\\geq', '<<': '\\ll', '>>': '\\gg', }; for (var key in replacements) { str = str.replace(key, replacements[key]); } this.parsed = this._parse_multi_part_number(str); }, _parse_multi_part_number: function (str) { var m = this.regex.exec(str); if (!m) { return str; } var ret = this._parse_full_number(m); while (m[10]) { // an additional part is available: var bracket = false; if (m[10] == this.options['input-quotient']) { ret += this.options['output-quotient']; bracket = true; } else { ret += this.options['output-product']; } m = this.regex.exec(m[11]); ret += this._parse_full_number(m, bracket); } return ret; }, _parse_full_number: function (m, bracket_exponent) { var opts = this.options; function PSign(sign) { return sign; } function PNumber(integer, decimal) { var gd = opts['group-digits']; var md = opts['group-minimum-digits']; var gs = '{' + opts['group-separator'] + '}'; integer = integer || '0'; var l = integer.length; if (l >= md && (gd == 'true' || gd == 'integer')) { l -= 3; for (; l > 0; l -= 3) { integer = integer.slice(0, l) + gs + integer.slice(l); } } if (!decimal) return integer; l = decimal.length; if (l >= md && (gd == 'true' || gd == 'decimal')) { l -= 1 + (l - 1) % 3; for (; l > 0; l -= 3) { decimal = decimal.slice(0, l) + gs + decimal.slice(l); } } return integer + '{' + opts['output-decimal-marker'] + '}' + decimal; } var exp = !!m[9]; if (!(m[2] || m[3] || m[4]) && exp) { // non-complex number without mantissa return (m[1] ? PSign(m[1]) : '') + '10^{' + m[9] + '}'; } var ret = (m[1] ? PSign(m[1]) : '') + PNumber(m[2], m[3]); var cplx = !!m[4]; if (cplx) { // have a complex number: ret += PSign(m[4]); if (opts['complex-root-position'] === 'before-number') ret += opts['output-complex-root'] + PNumber(m[5] || m[7], m[6] || m[8]); else ret += PNumber(m[5] || m[7], m[6] || m[8]) + opts['output-complex-root']; } if (exp) { if (cplx) { ret = '\\left(' + ret + '\\right)'; } ret += opts['exponent-product'] + ' ' + opts['exponent-base'] + '^{' + m[9] + '}'; if (bracket_exponent) ret = '\\left(' + ret + '\\right)'; } return ret; }, mml: function () { return TEX.Parse(this.parsed).mml(); } }); var SINumberListParser = exports.SINumberListParser = SINumberParser.Subclass({ Parse: function () { // TODO: do not process list separators via TeX parsing var str = this.string.replace(/\s+/gi, ''); var numbers = str.split(';'); var parsed = []; for (var idx = 0; idx < numbers.length; ++idx) { if (idx == numbers.length - 1) { if (idx == 1) { parsed.push('\\text{' + this.options['list-pair-separator'] + '}'); } else if (idx) { parsed.push('\\text{' + this.options['list-final-separator'] + '}'); } } else if (idx) { parsed.push('\\text{' + this.options['list-separator'] + '}'); } parsed.push(this._parse_multi_part_number(numbers[idx])); } this.parsed = parsed; }, mml: function () { return TEX.Parse(this.parsed.join('')).mml(); } }); return exports; });