/* eslint-disable no-nested-ternary */ /* eslint-disable no-restricted-syntax */ /* eslint-disable guard-for-in */ /** * num 小于0,左缩进num*2个空格; 大于0,右缩进num*2个空格。 * @param {string} str 代码 * @param {number} num 缩进次数 * @param {number} len 【可选】缩进单位,空格数 */ export function indent(str, num, len = 2) { if (num === 0) return str const isLeft = num < 0; const result = []; let reg; let spaces = '' if (isLeft) { num *= -1 reg = new RegExp(`(^\\s{0,${num * len}})`, 'g') } else { for (let i = 0; i < num * len; i++) spaces += ' ' } str.split('\n').forEach(line => { line = isLeft ? line.replace(reg, '') : spaces + line result.push(line) }) return result.join('\n') } // 首字母大小 export function titleCase(str) { return str.replace(/( |^)[a-z]/g, L => L.toUpperCase()) } // 下划转驼峰 export function camelCase(str) { return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase()) } export function isNumberStr(str) { return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str) } export const exportDefault = 'export default ' export const beautifierConf = { html: { indent_size: '2', indent_char: ' ', max_preserve_newlines: '-1', preserve_newlines: false, keep_array_indentation: false, break_chained_methods: false, indent_scripts: 'separate', brace_style: 'end-expand', space_before_conditional: true, unescape_strings: false, jslint_happy: false, end_with_newline: true, wrap_line_length: '110', indent_inner_html: true, comma_first: false, e4x: true, indent_empty_lines: true }, js: { indent_size: '2', indent_char: ' ', max_preserve_newlines: '-1', preserve_newlines: false, keep_array_indentation: false, break_chained_methods: false, indent_scripts: 'normal', brace_style: 'end-expand', space_before_conditional: true, unescape_strings: false, jslint_happy: true, end_with_newline: true, wrap_line_length: '110', indent_inner_html: true, comma_first: false, e4x: true, indent_empty_lines: true } } function stringify(obj) { return JSON.stringify(obj, (key, val) => { if (typeof val === 'function') { return `${val}` } return val }) } function parse(str) { JSON.parse(str, (k, v) => { if (v.indexOf && v.indexOf('function') > -1) { return eval(`(${v})`) } return v }) } export function jsonClone(obj) { return parse(stringify(obj)) } // 深拷贝对象 export function deepClone(obj) { const _toString = Object.prototype.toString // null, undefined, non-object, function if (!obj || typeof obj !== 'object') { return obj } // DOM Node if (obj.nodeType && 'cloneNode' in obj) { return obj.cloneNode(true) } // Date if (_toString.call(obj) === '[object Date]') { return new Date(obj.getTime()) } // RegExp if (_toString.call(obj) === '[object RegExp]') { const flags = [] if (obj.global) { flags.push('g') } if (obj.multiline) { flags.push('m') } if (obj.ignoreCase) { flags.push('i') } return new RegExp(obj.source, flags.join('')) } const result = Array.isArray(obj) ? [] : obj.constructor ? new obj.constructor() : {} for (const key in obj) { result[key] = deepClone(obj[key]) } return result } /** * 金额转中文 * 思路: * 个 * 十 百 千 万 * 十万 百万 千万 亿 * 十亿 百亿 千亿 * * 1 * 2 3 4 5 * 6 7 8 9 * 10 * * 计算步骤 * 1. 获取当前数值大小 * 2. 排除个位后 数值按个,十,百,千有规律的重复 所以计算其和4的余数 pos % 4 * 3. pos = 0 ~ 3 没有最大单位 * pos = 4 ~ 7 最大单位是万 * pos = 8 ~ 11 最大单位是亿 * pos / 4 的整数就是最大单位 * */ export function getAmountChinese(val) { const amount = +val if (Number.isNaN(amount) || amount < 0) return '' const NUMBER = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'] const N_UNIT1 = ['', '拾', '佰', '仟'] const N_UNIT2 = ['', '万', '亿'] const D_UNIT = ['角', '分', '厘', '毫'] let [integer, decimal] = amount.toString().split('.') if (integer && integer.length > 12) return '金额过大无法计算' let res = '' // 整数部分 if (integer) { for (let i = 0, len = integer.length; i < len; i++) { const num = integer.charAt(i) const pos = len - i - 1 // 排除个位后 所处的索引位置 if (num === '0') { // 当前位 等于 0 且下一位也等于 0 则可跳过计算 if (i === len - 1) { if (integer.length === 1) res += '零' // 0.35 这种情况不可跳过计算 break } if (integer.charAt(i + 1) === '0') continue } res += NUMBER[num] if (parseInt(num)) res += N_UNIT1[(pos) % 4] if (pos % 4 === 0) res += N_UNIT2[Math.floor(pos / 4)] } } res += '圆' // 小数部分 if (parseInt(decimal)) { for (let i = 0; i < 4; i++) { const num = decimal.charAt(i) if (parseInt(num)) res += NUMBER[num] + D_UNIT[i] } } else { res += '整' } return res } /** * 将用户输入的连续单个数字合并为一个数 * @param {Array} expressions - 记录计算表达式的数组 * @returns {Array} 新的数组 */ export const mergeNumberOfExps = expressions => { const res = [] const isNumChar = n => /^[\d|\.]$/.test(n) for (let i = 0; i < expressions.length; i++) { if (i > 0 && isNumChar(expressions[i - 1]) && isNumChar(expressions[i])) { res[res.length - 1] += expressions[i] continue } res.push(expressions[i]) } return res } /** * 校验表达式是否符合计算法则 * @param {Array} expressions - 合并数字后的表达式数组 * @returns {Boolean} */ export const validExp = (expressions, mergeNum = true) => { const temp = mergeNum ? mergeNumberOfExps(expressions) : expressions const arr = temp.filter(t => !'()'.includes(t)) // 去括号后 length应该为奇数 并且第一个字符和最后一个字符应该为数字而非计算符号 if (temp.length % 2 === 0 || arr.length % 2 === 0 || Number.isNaN(+arr[0]) || Number.isNaN(+arr[arr.length - 1])) { return false } for (let i = 0; i < arr.length - 1; i += 2) { if (typeof(+arr[i]) !== 'number' || !Number.isNaN(+arr[i + 1])) return false } return true } /** * 中缀转后缀(逆波兰 Reverse Polish Notation) * @param {Array} exps - 中缀表达式数组 */ export const toRPN = exps => { const s1 = [] // 符号栈 const s2 = [] // 输出栈 const getTopVal = (stack) => stack.length > 0 ? stack[stack.length - 1] : null const levelCompare = (c1, c2) => { const getIndex = c => ['+-', '×÷', '()'].findIndex(t => t.includes(c)) return getIndex(c1) - getIndex(c2) } exps.forEach(t => { if (typeof t === 'string' && Number.isNaN(Number(t))) { // 是符号 if (t === '(') { s1.push(t) } else if (t === ')') { let popVal do { popVal = s1.pop() popVal !== '(' && s2.push(popVal) } while (s1.length && popVal !== '(') } else { let topVal = getTopVal(s1) if (!topVal) { // s1 为空 直接push s1.push(t) } else { while (topVal && topVal !== '(' && levelCompare(topVal, t) >= 0) { // 优先级 >= t 弹出到s2 s2.push(s1.pop()) topVal = getTopVal(s1) } s1.push(t) } } return } s2.push(t) // 数字直接入栈 }) while (s1.length) { s2.push(s1.pop()) } return s2 } /** * 计算后缀表达式的值 * @param {Array} rpnExps - 后缀表达式 */ export const calcRPN = rpnExps => { rpnExps = rpnExps.concat() const calc = (x, y, type) => { let a1 = Number(x), a2 = Number(y) switch (type) { case '+': return a1 + a2; case '-': return a1 - a2; case '×': return a1 * a2; case '÷': return a1 / a2; } } for (let i = 2; i < rpnExps.length; i++) { if ('+-×÷'.includes(rpnExps[i])) { let val = calc(rpnExps[i - 2], rpnExps[i - 1], rpnExps[i]) rpnExps.splice(i - 2, 3, val) i = i - 2 } } return rpnExps[0] } /** * 简易防抖函数 * @param {Function} func -防抖目标函数 * @param {Number} gap - 防抖时间间隔 */ export const debounce = (func, gap) => { let timer return function() { timer && clearTimeout(timer) timer = setTimeout(() => { func.apply(this, arguments) }, gap) } }