Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

a-calc

Package Overview
Dependencies
Maintainers
1
Versions
161
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

a-calc

JavaScript的精准四则运算库,支持复杂运算与格式化操作例如: 带单位计算,千分位, 灵活指定小数点位数,指定舍入规则

  • 1.0.2
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
29K
increased by25.99%
Maintainers
1
Weekly downloads
 
Created
Source

a-calc

来源于实际业务的字符串四则运算的库, 可解决以下问题(注意1.0.2有破坏性更新!):

  • js数字计算精度问题
  • 数字计算可能输出科学计数法
  • 数字格式化, 数字千分位输出, 数字直接格式化成百分比, 保留数字的正负号, 直接输出分数等
  • 带单位的数字计算或格式化, 例如: 0.1% + 2%
  • 科学计数法写法的计算, 例如:-2e3 + 6
  • 支持四种舍入规则:去尾、进一、四舍五入、四舍六入(一种更精准的方法)

支持的运算符 : + - * / % **

安装

npm install a-calc

引入

commonjs

const {calc, fmt} = require("a-calc")
// 或者
const {calc, fmt} = require("a-calc/cjs") // 注意这个写法是明确指定使用cjs版本这是有意义的, 有些打包工具会对语法做转换, 直接写 a-calc 不好使(nuxt.js就是), 那就换成 a-calc/cjs 试试

es module

import {calc, fmt} from "a-calc"
// 或者
const {calc, fmt} from "a-calc/es"

browser

<script src="node_modules/a-calc/browser/index.js"></script>
<script>
const {calc, fmt} = a_calc
</script>

四则运算(支持科学计数法写法)

calc("0.1 + 0.2") // 0.3

// 复杂一点的计算
calc("0.1 + 0.2 * 0.3 / 0.4 * (0.5 + 0.6)") // 0.265

// 科学计数法的计算
calc("-2e2 + 3e+2") // 100

关于空格

空格在无歧义的情况下是非必须的,甚至可以正确解析下面人眼都难以解析的写法calc("-2e+2+3e+2"),但是没有人应该这样编写计算式来考验a-calc解析能力,请记住始终在你的计算式包含空格,这样也更漂亮和清晰,就像我写的示例那样!!!

顺便举个有歧义的计算式 calc("50%%2", {_unit: true})这种歧义显然是在带单位计算的时候出现,由于解析器不知道你的单位是% 还是 %% 所以你要用空格给出明确的意思,正确的写法应该是 calc("50% % 2", {_unit: true})

总之始终加空格!

填充变量并计算(重要)

计算后的值为精准值且不会出现科学计数法

let a = 0.000001
let b = 888.789
calc("a + b", {a,b}) // 0.000001 + 888.789 = 888.789001

calc("a * (b + c) % d + 7.123", [
    {a: 1, b: 2},
    {c: 3, d: 4}
]) // 8.123

// 复杂一点的
calc("1 + o.a / arr[0].d",{
    o: { a: 2 },
    arr: [{ d: 8 }]
}) // 1.25

calc("a + b - c",[
    {a: 1},
    {b: 2, c: 3}
])

带单位的计算

实际情况不总是那么理想, 也许我们不得不计算两个百分比数字, 幸好现在a-calc支持这些操作, 但是请注意,单位会从第一个携带单位的数字上取, 后面的单位会被忽略

// 要特别注意 _unit是必须的, 且不是默认开启的, 这是因为带单位的计算会额外做一些操作, 相比之下单纯的数字计算更快
calc("1 + 2%", {_unit: true}) // 3%

calc("1.123$$$ + 2.88% | + =6", {_unit: true}) // +4.003000$$$

1.0.2 之后带单位的计算可以有更多的参数,_unit 的取值可以为boolean | "on" | "off" | "auto" | "space" 参数看起来很多其实和之前的用法差不多, true "on" "auto" 这三个值的效果是一样的,表示自动识别数字后的单位,false "off" 表示关闭单位计算,最大的不同是 "space" 这个值表示只将空格作为单位分隔符,例如你的单位恰好是 +- 这种情况在普通模式下会被识别成运算符,就可以使用 "space" 模式,但是此时的空格就是必须的了,你要这样写:calc("2+- * 3") 最终结果为:6+-

计算并格式化

格式化支持如下功能:限制小数位数,保留正负号,百分比输出,科学计数法输出,千分位输出,并且他们是可以组合的,不过有个别的情况组合是不生效的,这个自己去试一下,组合情况太多,不在一一列举。

// 操作小数位数
calc("0.1 + 0.2 | =2") // 0.30
calc("0.11111 + 0.11111 | <=4") // 0.2222
calc("0.11 + 0.11 | <=4") // 0.22
calc("0.1 + 0.2 | >= 5") // 0.30000
calc("0.0000001+ 0.0000001 | >= 5") // 0.0000002

// 格式化的时候对于小数位的操作只支持 >=    <=    =   三种符号

// 保留正负号
calc("1 + 1 | +") // +2

// 千分位
calc("10000000 + 100000000 | ,") // 110,000,000

// 百分比
calc("1 + 1 | %") // 200%

// 科学计数法, 注意这里由于是普通字符串所以要用\\e,这个 e也可以大写
calc("1 + 1 | \\e") // 2e+0

// 同时指定小数位和千分位且保留正负号
calc("10000000 + 100000000 | +,=10") // +110,000,000.0000000000

四种舍入规则

舍入规则通过在格式化字符串的部分加入,他们的符号分别为:

  • ~- 去尾,默认的舍入规则
  • ~+ 进一
  • ~5 四舍五入
  • ~6 四舍六入,该舍入规则相较四舍五入更为精准,规则在舍入的后一位为5的时候有所不同,他会查看5后面的位置,如果后面的数字不为0那么会进一,如果后面的数字为0 ,那么会看5前面的数字是否为偶数,如果是则不进,不是则进
calc("0.11 + 0.22 | =1 ~+") // 0.4 保留一位并进一
calc("0.55 | =1 ~5") // 0.6
calc("0.65 | =1 ~6") // 0.6

这个新加入的舍入规则似乎会让格式化的部分更加的长,但是实际情况不是这样,一般一个项目的舍入规则是固定的,所以舍入规则部分的格式化应该被封装在默认的格式化参数中,在实际使用的时候完全不需要书写这部分内容,参考下面的默认格式化 说明

只格式化

calc("0.1 | =2") // 0.10
fmt("0.1 | =2") // 0.10
// calc 具备 fmt 的功能, 但是fmt具备更好的语义

fmt("1000000 | ,") // 1,000,000

高级技巧

错误处理

通常直接使用calc做计算要求输入的计算式是完全正确的, 默认 a-calc 不会帮你处理计算式的错误, 这个可以自己做过滤, 但在项目里我们可能不想做这件事情那么就需要额外的高级API, 在输入的计算式有误的时候静默捕获并给出一个合适的返回值

calc("1 + 2sd + d",{
    _fill_data: {d: 3}, // 从这里数据源对象要赋给 _fill_data, 该对象也可以是一个对象数组,此时取数据的时候是依次从数组的项里查找,找到第一个立刻停止
    _error: "-", // 计算式出错的时候返回 - 作为替代值
})

// 上面的写法可以简化一下
calc("1 + 2sd + d", {
    d: 8,
    _error: "-"
}) // 这种简化单纯是为了方便

默认格式化

在实际项目中可以利用默认格式化优化开发体验

calc("111111 + 11111 | ,",{_fmt: "=2"}) // 122,222.00 很显然 , 和 =2 被组合起来了,且表达式中的格式化字符串优先级更高

在项目中的使用姿势(vue3为例)

在项目中编写庞大的第二个参数是不好的, 所以第二个参数你应该想办法固定他, 下面只是一个在VUE项目中的演示

集成到vue3模板

import { calc, fmt } from "a-calc";
import type { App } from "vue";
import { getCurrentInstance } from "vue";

function bind_calc ( app: App<Element> )
{
    // 接受一个app的实例绑定计算器

    app.config.globalProperties.calc = function ( expr: string, obj: any )
    {
        const instance: any = getCurrentInstance();
        const data_arr = [ instance.setupState, instance.data ];
        let _fmt, _error, _unit;

        if ( obj !== undefined ) {
            dataArr.unshift( obj );
            _fmt = obj._fmt === undefined ? undefined : obj._fmt;
            _error = obj._error === undefined ? undefined : obj._error;
            _unit = obj._unit === undefined ? undefined : obj._unit;

        }

        return calc( expr, {
            _fill_data: data_arr,
            _error: _error === undefined ? "-" : _error,
            _fmt, // 格式化参数在没有字符串格式化的时候才有用
            _unit
        } );
    };

    app.config.globalProperties.fmt = function ( expr: string, obj: any )
    {
        // 专门格式化的
        const instance: any = getCurrentInstance();
        const dataArr = [ instance.setupState, instance.data ];
        let _fmt, _error, _unit;

        if ( obj !== undefined ) {
            dataArr.unshift( obj );
            _fmt = obj._fmt === undefined ? undefined : obj._fmt;
            _error = obj._error === undefined ? undefined : obj._error;
            _unit = obj._unit === undefined ? undefined : obj._unit;
        }

        return fmt( expr,
                {
                    _fill_data: data_arr,
                    _error: _error === undefined ? "-" : _error,
                    _fmt,
                    _unit
                } );
    };

}

集成到script setup中

interface CalcConfig
{
    _fmt?: string;
    _error: string;
    _unit?: boolean;
}

function use_calc ( state: ReactiveVariable<any>, config: CalcConfig = { _error: "-" } )
{
    const data_arr = [ state ];

    const _fmt = config._fmt === undefined ? undefined : config._fmt;
    const _error = config._error === undefined ? undefined : config._error;
    const _unit = config._unit === undefined ? undefined : config._unit;


    return function ( expr: string, data = {} )
    {
        data_arr.unshift( data );
        return calc( expr, {
            _fill_data: data_arr,
            _error: _error === undefined ? "-" : _error,
            _fmt, // 格式化参数在没有字符串格式化的时候才有用
            _unit
        } );
    };
}

下面是使用示例

<script lang="ts" setup>
const state = reactive({
    a: 1,
    b: 2,
    c: 3
})

const calc = use_calc(state)

calc("a + b * c")
</script>

版本变更

  • 1.0.2
    • 破坏性变更:所有暴露出的小驼峰命名全部改成了蛇形命名法例如原来的_fillData 现在变成了 _fill_data,原因是蛇形命名法更清晰。
    • 内部代码极大的简化,解析器几乎完全重写,带来更稳定的体验
    • 原先的设计就是calc函数具备所有fmt的功能,可是1.0.2 之前的版本虽然符合这个设计可是calc和fmt是分别实现的,现在fmt只是calc的别名。
    • 支持新的运算符 **
    • 支持新的格式化字符 % 可以将数字输出成百分比
    • 支持新的格式化字符 \e,可以将数字格式化成科学计数法
    • 修复格式化字符串非法的时候可能造成死循环的问题
    • 解决1/0是 Infinity 的问题
    • 增加若干单元测试
    • 更详细的类型提示
    • 更新文档,添加vue3集成的示例代码
  • 0.0.80
    • 带来4种舍入规则,分别为:去尾、进一、四舍五入、四舍六入
    • 更多边界情况的检测
    • fmt允许不传入格式化字符串,这个特性允许你使用 fmt 来清除小数点后多余的0
  • 0.0.79
    • 更新文档
  • 0.0.78
    • 支持科学计数法的计算
    • 完整的单元测试
    • 更多边界情况的检测
  • 0.0.72
    • 支持单个数值的带单位写法, 例如 calc("1元", {_unit: true}) 或者 fmt("1元 | =2",{_unit: true})
    • 补充文档

注意

  • 不要对单个数字包裹括号

视频教程

待定

问题提交

(如果遇到了什么问题, 请第一时间向我发送反馈邮件, 718879459@qq.com 对于bug我会第一时间修复他)

Keywords

FAQs

Package last updated on 27 Mar 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc