UNPKG

mofang-mopai-utils

Version:

Use it in Mopai system

179 lines (169 loc) 6.85 kB
/** * A class for performing mathematical calculations on a given formula. * 魔方魔派前端计算器 */ class MofangMopaiCalculator { _formula: string /** * Constructs a new instance of MfCalculator. * * @param {string} formula - The mathematical formula to be calculated. * @throws Will throw an error if the formula is not provided or is not a string. */ constructor(formula: string){ if(!formula) throw new Error('[传参错误] - 传入公式不能为空') if(typeof formula !== 'string') throw new Error('[传参错误] - 传入公式必须是字符串格式') this._formula = formula.replace(/\s*/g, '') } /** * Calculates the final result of the mathematical formula. * * @returns {number} The final result of the calculation. */ get(): number { const res = this._splitFormula(this._formula) return Number(res || 0) } /** * Splits the mathematical formula into smaller parts for individual calculation. * It continues to do this until there are no more operators left in the formula. * * @param {string} formula - The mathematical formula to be split. * @returns {string} The final result of the calculation. * * @example * _splitFormula('1.23+34.23+33-4-7.8*8.12+103.21') // returns '104.334' */ _splitFormula(str: string): string{ // 先乘除 后加减 const methodA = str.match(/\*|\//) // 判断有没有乘除法公式 const methodB = str.match(/\+|\-/) // 判断有没有加减法公式 // 如果未匹配到计算公式,则是计算后的最终结果,直接返回 if(!methodA && !methodB) return str // 定义计算公式正则表达式 let reg: RegExp if(methodA){ reg = this._getRegExp(methodA[0]) } else if(methodB){ reg = this._getRegExp(methodB[0]) } else { throw new Error('[计算错误] - 未能成功获得计算公式正则表达式') } // 匹配字符串中的计算公式 const arr: string[] | null = str.match(reg) const formula: string = arr?.[0] || '' if(!formula) throw new Error('[计算错误] - 未匹配到计算公式') // 对公式进行计算 const calculationResult: number = this._startCalc(formula) // 把相应的计算公式替换成计算后的结果值 const replaceFormula = str.replace(formula, calculationResult.toString()) // 继续进行计算 直到字符串中没有计算公式为止 return this._splitFormula(replaceFormula) } /** * Gets a regular expression based on the given calculation method. * * @param {string} method - The calculation method. * @returns {RegExp} The regular expression. */ _getRegExp(method: string): RegExp{ return new RegExp(`\\d+(\\.\\d+)?\\${method}\\d+(\\.\\d+)?`) } /** * Starts the calculation process for a given formula. * * @param {string} formula - The mathematical formula to be calculated. * @returns {number} The result of the calculation. * * @example * _startCalc('1.23+34.23') // returns 35.46 * _startCalc('34.23-33') // returns 1.23 * _startCalc('33*7.8') // returns 257.4 * _startCalc('103.21/8.12') // returns 12.699999999999998 */ _startCalc(formula: string): number{ if(!formula) throw new Error('[计算错误] - 未找到需要计算的公式') const reg = /\+|\-|\*|\//g const method = formula.match(reg)?.[0] // 获取计算符 if(!method) throw new Error('[计算错误] - 计算方法错误') const numArray = formula.split(reg) return this._execMath(numArray[0], numArray[1], method) } /** * Executes a mathematical operation on two numbers. * * @param {number | string} [a=0] - The first number. * @param {number | string} [b=0] - The second number. * @param {string} method - The mathematical operation to be performed. * @returns {number} The result of the mathematical operation. * @throws Will throw an error if the method is not one of the following: '+', '-', '*', '/'. * * @example * _execMath(1.23, 34.23, '+') // returns 35.46 * _execMath(34.23, 33, '-') // returns 1.23 * _execMath(33, 7.8, '*') // returns 257.4 * _execMath(103.21, 8.12, '/') // returns 12.699999999999998 */ _execMath(a: number | string = 0, b: number | string = 0, method: string): number{ // 获取小数点后位数 const decimalLength = Math.max(this._getDecimalLength(a), this._getDecimalLength(b)) const x = this._transformToInteger(a, decimalLength) // 补位后的a值 const y = this._transformToInteger(b, decimalLength) // 补位后的b值 const z = Number(('1').padEnd(decimalLength + 1, '0')) // 补位数 switch (method) { case '+': { return (x + y) / z } case '-': { return (x - y) / z } case '*': { return x * y / Math.pow(z, 2) } case '/': { return x / y } default: { return 0 } } } /** * Gets the decimal length of a number. * * @param {number} num - The number to get the decimal length from. * @returns {number} The decimal length of the number. * * @example * _getDecimalLength(1.23) // returns 2 * _getDecimalLength(34.23) // returns 2 * _getDecimalLength(33) // returns 0 */ _getDecimalLength(num: string | number): number{ const n = num.toString() const arr = n.split(/\./) return arr[1]?.length || 0 } /** * Transforms a decimal number into an integer by padding the decimal part with zeros. * !因为直接进位计算还是会出现小数点后无穷位的问题,所以直接用字符串进行格式化 * * @param {number} num - The decimal number to be transformed. * @param {number} offset - The number of decimal places to pad. * @returns {number} The transformed integer. * * @example * _transformToInteger(1.23, 2) // returns 123 * _transformToInteger(34.23, 3) // returns 34230 * _transformToInteger(33, 1) // returns 330 */ _transformToInteger(num: string | number, offset: number): number{ if(offset === 0) return Number(num) const n = num.toString() const arr = n.split(/\./) const dec = arr[1]?.toString() || '0' arr[1] = dec.padEnd(offset, '0') return Number(arr.join('')) } } export default MofangMopaiCalculator