@cloudcome/utils-core
Version:
cloudcome core utils
1 lines • 18.6 kB
Source Map (JSON)
{"version":3,"file":"string2.cjs","sources":["../src/number.ts","../src/string.ts"],"sourcesContent":["import { objectDefaults } from './object';\nimport { STRING_DICT } from './string';\nimport { isNumber } from './type';\n\nexport type NumberFixedOptions = {\n /**\n * 保留的小数位数\n * @default 0\n */\n decimals?: number;\n\n /**\n * 舍入方法,0 为四舍五入,1 为向上取整,-1 为向下取整\n * @default 0\n */\n round?: 0 | 1 | -1;\n};\n\n/**\n * 对数字进行精确小数位数处理并按规则舍入\n * @param number 需要处理的原始数值\n * @param options 可选配置参数\n * @returns 处理后的数值(number类型)\n * @example\n * // 四舍五入示例\n * numberFixed(3.1415, { decimals: 2 }); // 3.14\n * // 向上取整示例\n * numberFixed(3.1415, { decimals: 2, round: 1 }); // 3.15\n * // 向下取整示例\n * numberFixed(3.9999, { decimals: 1, round: -1 }); // 3.9\n */\nexport function numberFixed(number: number, options?: NumberFixedOptions) {\n const { decimals = 0, round = 0 } = options || {};\n const scale = 10 ** decimals;\n\n if (round === 1) {\n return Math.ceil(number * scale) / scale;\n }\n\n if (round === -1) {\n return Math.floor(number * scale) / scale;\n }\n\n return Math.round(number * scale) / scale;\n}\n\n/**\n * 生成指定范围内的随机数\n * @param {number | string} min - 随机数的最小值(包含,支持小数、字符串)\n * @param {number | string} max - 随机数的最大值(包含,支持小数、字符串)\n * @returns {number} - 生成的随机数\n * @example\n * // 生成 1 到 10 之间的随机整数\n * randomNumber(1, 10); // 可能返回 7\n *\n * // 生成 0.1 到 2 之间的一位随机小数\n * randomNumber(0.1, 2); // 可能返回 0.7\n *\n * // 生成 0.10 到 2 之间的两位随机小数\n * randomNumber(\"0.10\", 2); // 可能返回 0.75\n */\nexport function randomNumber(min: number | string, max: number | string): number {\n const minDecimals = numberDecimals(min);\n const maxDecimals = numberDecimals(max);\n const decimals = Math.max(minDecimals, maxDecimals);\n const scale = 10 ** decimals;\n\n const minNum = Number(min);\n const maxNum = Number(max);\n const [minFinal, maxFinal] = minNum > maxNum ? [maxNum, minNum] : [minNum, maxNum];\n\n const scaledMin = minFinal * scale;\n const scaledMax = maxFinal * scale;\n\n return Math.floor(Math.random() * (scaledMax - scaledMin + 1) + scaledMin) / scale;\n}\n\n/**\n * 数字缩写选项\n */\nexport type NumberAbbrOptions = {\n /**\n * 进制基数,用于计算单位进阶(如 1000 表示千进制)\n * @default 1000\n */\n base?: number;\n\n /**\n * 数值保留的小数位数\n * @default 0\n */\n decimals?: number;\n};\n\n/**\n * 将数字转换为带单位缩写的字符串表示\n *\n * @param {number} number - 需要转换的原始数值\n * @param {Array<string>} units - 单位数组,按从小到大顺序排列(如['B','KB','MB']),不能为空\n * @param {NumberAbbrOptions} [options] - 可选配置参数\n * @returns {string} - 转换后的带单位字符串(如\"1.2KB\")\n * @example\n * // 基础用法\n * numberAbbr(1500, ['', 'K', 'M'], { base: 1000 }); // \"1.5K\"\n * @example\n * // 自定义小数位\n * numberAbbr(123456, ['B','KB','MB'], { decimals: 1 }); // \"0.1MB\"\n * @example\n * // 处理不足基数的情况\n * numberAbbr(500, ['B','KB']); // \"500B\"\n */\nexport function numberAbbr(number: number, units: Array<string>, options?: NumberAbbrOptions): string {\n const { base = 1000, decimals = 0 } = options || {};\n const { length } = units;\n\n if (length === 0) throw new Error('数字单位组不能为空');\n\n let numberFinal = number;\n let step = 0;\n\n while (numberFinal >= base && step < length - 1) {\n numberFinal = numberFinal / base;\n step++;\n }\n\n const value = numberFixed(numberFinal, { decimals: decimals, round: -1 });\n const unit = units[step];\n\n return `${value}${unit}`;\n}\n\n/**\n * 将文件大小转换为带单位缩写的字符串表示\n *\n * @param {number} number - 需要转换的文件大小数值\n * @param {number} [decimals=0] - 数值保留的小数位数\n * @returns {string} - 转换后的带单位字符串(如\"1.2KB\")\n * @example\n * // 基础用法\n * fileSizeAbbr(1024); // \"1KB\"\n * @example\n * // 自定义小数位\n * fileSizeAbbr(123456, 1); // \"0.1MB\"\n */\nexport function fileSizeAbbr(number: number, decimals = 0) {\n return numberAbbr(number, ['B', 'KB', 'MB', 'GB', 'TB'], {\n base: 1024,\n decimals: decimals,\n });\n}\n\n/**\n * 将十进制数转换为指定进制的字符串表示\n *\n * @param {number | bigint} decimal - 需要转换的十进制数,可以是任意长度的数字或大整数\n * @param {string} [dict] - 用于表示进制的字符字典,默认为数字、小写字母和大写字母的组合(62 进制)\n * @returns {string} - 转换后的指定进制字符串\n * @throws {Error} - 如果字符字典的长度小于 2,将抛出错误\n * @example\n * // 默认 62 进制\n * numberConvert(123456789); // \"8M0kX\"\n * @example\n * // 自定义 16 进制\n * numberConvert(255, '0123456789ABCDEF'); // \"FF\"\n * @example\n * // 处理大整数\n * numberConvert(9007199254740991n); // \"2gosa7pa2GV\"\n */\nexport function numberConvert(decimal: number | bigint, dict?: string): string {\n const dictFinal = dict || STRING_DICT;\n\n if (dictFinal.length < 2) throw new Error('进制转换字典长度不能小于 2');\n\n let bigInt = BigInt(decimal);\n const symbol = bigInt < 0n ? '-' : '';\n bigInt = bigInt < 0n ? -bigInt : bigInt;\n const result: Array<string> = [];\n const { length } = dictFinal;\n const bigLength = BigInt(length);\n const calculate = (): void => {\n const y = Number(bigInt % bigLength);\n\n bigInt = bigInt / bigLength;\n result.unshift(dictFinal[y]);\n\n if (bigInt > 0) {\n calculate();\n }\n };\n\n calculate();\n\n return symbol + result.join('');\n}\n\n/**\n * 数字格式化配置选项\n */\nexport type NumberFormatOptions = {\n /**\n * 分隔符字符,用于数字分隔\n * @default ','\n * @example 使用 '_' 分隔符时,123456 会格式化为 '123_456'\n */\n separator?: string;\n\n /**\n * 分隔步长,即每隔多少位添加分隔符\n * @default 3\n * @example 步长为 2 时,123456 会格式化为 '12,34,56'\n */\n step?: number;\n};\n\n/**\n * 数字格式化\n * @param [number] {number} 数字\n * @param options {NumberFormatOptions} 格式化配置\n * @returns {string} 分割后的字符串\n * @example\n * // 使用默认分隔符和步长\n * numberFormat(123456.789); // => \"123,456.789\"\n * // 自定义分隔符\n * numberFormat(123456.789, '_'); // => \"123_456.789\"\n * // 自定义步长\n * numberFormat(123456.789, 2); // => \"12,34,56.789\"\n * // 使用对象配置\n * numberFormat(123456.789, { separator: '.', step: 4 }); // => \"12.3456.789\"\n */\nexport function numberFormat(number: number, options: NumberFormatOptions): string;\nexport function numberFormat(number: number, separator: string): string;\nexport function numberFormat(number: number, step: number): string;\nexport function numberFormat(number: number): string;\nexport function numberFormat(number: number, options?: NumberFormatOptions | string | number) {\n let optionsFinal: Required<NumberFormatOptions> = {\n separator: ',',\n step: 3,\n };\n\n if (typeof options === 'string') {\n optionsFinal.separator = options;\n } else if (typeof options === 'number') {\n optionsFinal.step = options;\n } else {\n optionsFinal = objectDefaults(options || {}, optionsFinal) as Required<NumberFormatOptions>;\n }\n\n const { separator, step } = optionsFinal;\n const arr = String(number).split('.');\n const re = new RegExp(`(\\\\d)(?=(\\\\d{${step}})+(?!\\\\d))`, 'g');\n const p1 = arr[0].replace(re, `$1${separator}`);\n\n return p1 + (arr[1] ? `.${arr[1]}` : '');\n}\n\n/**\n * 将数字限制在指定范围内。\n *\n * @param min - 最小值。\n * @param number - 要限制的数字。\n * @param max - 最大值。\n * @returns 限制后的数字。\n */\nexport function numberClamp(min: number, number: number, max: number) {\n return Math.min(Math.max(number, min), max);\n}\n\n/**\n * 为数字添加单位\n * @param number - 需要处理的数字,可以是数字类型或字符串类型\n * @param unit - 要添加的单位,默认为空字符串\n * @returns 如果输入是数字或纯数字字符串,则返回带单位的字符串;否则返回原值\n */\nexport function numberUnit(number: string | number, unit = '') {\n if (isNumber(number)) return `${number}${unit}`;\n if (/^-?[\\d.]+$/.test(number)) return `${number}${unit}`;\n return number;\n}\n\n/**\n * 获取数字的小数位数\n * @param num - 需要计算小数位数的数字或数字字符串\n * @returns 返回数字的小数位数,如果是整数则返回0\n * @example\n * // 基本用法\n * numberDecimals(3.1415); // 4\n * numberDecimals(\"3.1415\"); // 4\n * numberDecimals(100); // 0\n * numberDecimals(\"100\"); // 0\n * // 科学计数法\n * numberDecimals(\"1.23e-4\"); // 6\n */\nexport function numberDecimals(num: number | string) {\n const numStr = String(num);\n const matches = numStr.match(/(?:\\.(\\d+))?(?:e-(\\d+))?$/i);\n if (!matches) return 0;\n return (matches[1] || '').length + Number.parseInt(matches[2] || '0');\n}\n","import { numberConvert, randomNumber } from './number';\nimport { isFunction, isNullish, isNumber, isObject, isString, isUndefined } from './type';\n\n/** 阿拉伯数字字符集合 */\nexport const STRING_ARABIC_NUMERALS = '0123456789';\n/** 十六进制字符集合 */\nexport const STRING_HEXADECIMALS = '0123456789abcdef';\n/** 小写字母字符集合 */\nexport const STRING_LOWERCASE_ALPHA = 'abcdefghijklmnopqrstuvwxyz';\n/** 大写字母字符集合 */\nexport const STRING_UPPERCASE_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n/** 随机字符串字典,包含数字、大写字母和小写字母 */\nexport const STRING_DICT = `${STRING_ARABIC_NUMERALS + STRING_UPPERCASE_ALPHA + STRING_LOWERCASE_ALPHA}`;\n\n/**\n * 将字符串转换为驼峰格式\n * @param {string} string - 要转换的字符串\n * @param {boolean} [bigger] - 是否大写第一个字母,默认为 false\n * @returns {string} - 转换后的驼峰格式字符串\n */\nexport function stringCamelCase(string: string, bigger?: boolean): string {\n const string2 = string.replace(/[\\s_-](.)/g, (_, char) => (char as string).toUpperCase());\n return bigger ? string2.slice(0, 1).toUpperCase() + string2.slice(1) : string2;\n}\n\n/**\n * 将字符串转换为连字格式\n * @param {string} string - 要转换的字符串\n * @param {string} [separator] - 分隔符,默认是 \"-\"(短横线)\n * @returns {string} - 转换后的连字格式字符串\n */\nexport function stringKebabCase(string: string, separator = '-'): string {\n return string.replace(/[A-Z]/g, (origin) => `${separator}${origin.toLowerCase()}`);\n}\n\n/**\n * 生成随机字符串\n * @param {number} length - 生成的随机字符串长度\n * @param {string} [dict] - 用于生成随机字符串的字符字典,默认为数字、小写字母和大写字母的组合\n * @returns {string} - 生成的随机字符串\n * @example\n * randomString(10); // 生成一个长度为 10 的随机字符串\n * randomString(8, 'ABCDEF'); // 生成一个长度为 8 的随机字符串,仅包含字符 'ABCDEF'\n */\nexport function randomString(length: number, dict?: string): string {\n const dictFinal = dict || STRING_DICT;\n const dictLength = dictFinal.length;\n\n let result = '';\n\n for (let i = 0; i < length; i++) {\n result += dictFinal.charAt(randomNumber(0, dictLength - 1));\n }\n\n return result;\n}\n\n/**\n * 简单的模板引擎,类似于 Python 的 `.format()` 方法\n * 支持通过索引或对象/名称的方式传递变量\n * 当使用对象/名称方式时,可以传递一个回退值作为第三个参数\n *\n * @category 字符串\n * @example\n * ```\n * // 索引方式\n * const result = stringFormat(\n * '你好 {0}!我的名字是 {1}。',\n * '张三',\n * '李四'\n * ); // 你好 张三!我的名字是 李四。\n * ```\n *\n * @example\n * ```\n * // 对象方式\n * const result = stringFormat(\n * '{greet}!我的名字是 {name}。',\n * { greet: '你好', name: '王五' }\n * ); // 你好!我的名字是 王五。\n * ```\n *\n * @example\n * ```\n * // 带回退值的对象方式\n * const result = stringFormat(\n * '{greet}!我的名字是 {name}。',\n * { greet: '你好' }, // name 未传递,因此会使用回退值\n * '未知'\n * ); // 你好!我的名字是 未知。\n * ```\n */\nexport function stringFormat(\n str: string,\n object: Record<string | number, unknown>,\n fallback?: string | ((key: string) => string),\n): string;\nexport function stringFormat(str: string, ...args: (string | number | bigint | undefined | null)[]): string;\nexport function stringFormat(str: string, ...args: unknown[]): string {\n const [firstArg, fallback] = args;\n\n if (isObject(firstArg) || isUndefined(firstArg)) {\n const vars = firstArg || {};\n return str.replace(/\\{(\\w+)\\}/g, (_, key) => vars[key] ?? (isFunction(fallback) ? fallback(key) : fallback) ?? key);\n }\n\n return str.replace(/\\{(\\d+)\\}/g, (_, key) => {\n const index = Number(key);\n if (Number.isNaN(index)) return key;\n return args[index];\n });\n}\n\n/**\n * 生成符合 [RFC 4122](https://www.ietf.org/rfc/rfc4122.txt) 版本 4 的 UUID 字符串\n * @returns {string} - 生成的 UUID 字符串\n * @example\n * const uuid = randomUUID4();\n * console.log(uuid); // 输出类似 '123e4567-e89b-12d3-a456-426614174000' 的 UUID 字符串\n */\nexport function randomUUID4(): string {\n const template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';\n let result = '';\n\n for (let i = 0; i < template.length; i++) {\n const t = template[i];\n\n if (t === '-' || t === '4') {\n result += t;\n continue;\n }\n\n if (t === 'y') {\n result += randomString(1, '89ab');\n continue;\n }\n\n result += randomString(1, STRING_HEXADECIMALS);\n }\n\n return result;\n}\n\n/**\n * 将值转换为字符串,若值为 null 或 undefined 则返回空字符串\n * @param {unknown} value - 需要转换的值\n * @returns {string} 转换后的字符串结果\n */\nexport function stringify(value: unknown) {\n return isNullish(value) ? '' : String(value);\n}\n"],"names":["objectDefaults","isNumber","isObject","isUndefined","isFunction","isNullish"],"mappings":"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"}