HLC.Expression
字符串表达式公式解析计算; String expression formula parsing calculation;
Install / Use
/learn @houlongchao/HLC.ExpressionREADME
HLC.Expression 字符串表达式解析库
一款支持数学运算,逻辑运算,字符串运算,常用数学函数运算以及其它常用自定义函数运算的工具库。
高度抽象,快速扩展自定义函数
1. 功能说明
-
[x] 对字符串表达式进行解析计算
-
[x] 支持常用数学计算
-
[x] 支持常用逻辑运算
-
[x] 支持常用字符串运算
-
[x] 支持带入参数计算
-
[x] 支持参数负载属性计算
-
[x] 支持牛顿法求解一元函数
-
[x] 高度抽象,支持快速扩展自定义函数
-
[x] 支持非侵入自定义函数
2. 用途
- 自己想写个计算器但是不会做字符串解析(使用,研究,
Ctrl-CV大法皆可) - 项目中需要做数学运算来动态获取值
- 项目中需要自定义配置逻辑表达式来进行条件约束
3. 使用说明
3.1 安装使用
3.1.1 NuGet安装
NuGet中搜索HLCExpression进行安装使用
dotnet add package HLCExpression
3.1.2 不含参数计算
// 计算返回数值结果
Expression.From("CEILING(50.12+1)").Invoke().NumberResult
// 计算返回Boolean结果
Expression.From("2.1<=1.1").Invoke().BooleanResult
// 计算返回String结果
Expression.From("TOSTR(DATETIME('2021-01-01'), 'yyyy-MM-dd')").Invoke().StringResult
// 更多示例见代码单元测试
3.1.3 含参数计算
// 构建参数字典
var parameters = new Parameters()
{
{"num", 123456},
{"numlist1", new List<decimal>(){1,2,3,4,5}},
{"str", "abcde"},
{"strnum", "123.3"},
{"empty", ""},
{"true", true },
{"false", false },
{"strlist1", new List<string>(){"aaa","bbb","ccc"}},
{"range", new Parameter("(1,5)", ParameterType.Range)},
{"dt", new Parameter(DateTime.Parse("2021-01-01"))},
};
// 添加属性测试参数
parameters["metadata"] = new Parameter("metadataValue");
parameters["metadata"].Metadata["meta01"] = "value01";
parameters["metadata"].Metadata["meta02"] = "True";
parameters["metadata"].Metadata["meta03"] = "123";
// 获取指定参数的指定属性值
Expression.From("META({metadata}, 'meta01') == 'value01'").Invoke(parameters).BooleanResult
Expression.From("META({metadata}, 'meta03', 'num') == 123").Invoke(parameters).BooleanResult
// 计算表达式
var aaa = Expression.From("IN({str4},{strlist1}) && IN({str1},{strlist1}) || (1+2*3-4)==MAX(1+2,2)");
aaa.Invoke(parameters);
// 计算并返回boolean值
Expression.From("{strnum}<134").Invoke(parameters).BooleanResult
3.1.4 表达式设置
// 继承ExpressionSetting
// 重写里面的属性和方法
public class MySetting : ExpressionSetting
{
public override bool HasStringStartChar => false;
public override bool HasStringEndChar => false;
public override bool HasVariableEndChar => false;
public override char VariableStartChar => '$';
}
// 应用设置
ExpressionSetting.SetSetting(new MySetting());
3.1.5 牛顿法求一元函数
// 求参数num2的值
Expression.From("{num1}+{num2}+{num1}*{num2}-{num1}*4.5+{num2}*0.5").NewtonSolve("num2", parameters);
3.1.6 非侵入自定义函数
var parameters = new Parameters();
parameters.RegisterCallFunc("Concat", (arg) =>
{
return string.Concat(arg);
});
Assert.AreEqual("12345", Expression.From("CALL('concat', 1,2,3,4,2+3)").Invoke(parameters).StringResult);
3.2 支持的二元运算符
运算符前后空格会被忽略,但运算符不能被空格拆分。
| 符号 | 说明 | 优先级 | 约束 | 示例 | | ---- | ---- | ---- | -------------------------- | --------------- | | ^ | 指数 | 100 | 左右只能是数字或表达式结果为数字 | 5^2 | | % | 取模 | 50 | 左右只能是整数或表达式结果为整数 | 5%2 | | * | 乘法 | 50 | 左右只能是数字或表达式结果为数字 | 5*2 | | / | 除法 | 50 | 左右只能是数字或表达式结果为数字 | 5/2 | | + | 加法 | 40 | 左右只能是数字或表达式结果为数字 | 5+2 | | - | 减法 | 40 | 左右只能是数字或表达式结果为数字 | 5-2 | | > | 大于 | 30 | 左右只能是数字或表达式结果为数字 | 5>2 | | >= | 大于等于 | 30 | 左右只能是数字或表达式结果为数字 | 5>=2 | | < | 小于 | 30 | 左右只能是数字或表达式结果为数字 | 5<2 | | <= | 小于等于 | 30 | 左右只能是数字或表达式结果为数字 | 5<=2 | | == | 等于 | 30 | 左右只能是数字或表达式结果为数字 | 5==2 | | != | 不等于 | 30 | 左右只能是数字或表达式结果为数字 | 5!=2 | | && | 与 运算 | 20 | 左右只能是Boolean或表达式结果为Boolean | true && false | | || | 或 运算 | 10 | 左右只能是Boolean或表达式结果为Boolean | true || false | | | | | | |
3.3 支持的函数运算
函数名与后面的左括号之间不能有空格,参数前后可以有空格。
3.3.1 条件判断
| 函数 | 说明 | 简单示例 | 返回类型 |
| ----------- | ------ | ---------------------------------------- | ---- |
| IF() | 逻辑判断 | IF(1>2, true, 1) IF(1 > 2, 2 > 4, false) | 任意值 |
| SWITCH() | 精准开关匹配 | SWITCH({A}, 1:'str', 2:'2') SWITCH({A}, 'A':1, 'B':2) | 任意值 |
| SWITCHC() | 模糊开关匹配 | SWITCHC({A}, '1':'str', '2':'2') SWITCHC({A}, 'A':1, 'B':2) | 任意值 |
| | | | |
IF 逻辑判断
- 必须三个参数,第一个为要判断的逻辑值,在参数一为ture时返回第二个参数结果,否则返回第三个参数结果
IF(1>2,11,22)==>22
IF(1<2,11,22)==>11
SWITCH 精准开关匹配
- 第一个参数与后面参数匹配值(:前)相同时返回对应的结果值(:后)
SWITCH(1, 1:'A', 2:22, 3:'C')==>A
SWITCH(2, 1:'A', 2:22, 3:'C')==>22
SWITCHC 模糊开关匹配
- 第一个参数包含后面参数匹配值(:前)相同时返回对应的结果值(:后)
SWITCHC(123, 1:'A', 2:22, 3:'C')==>A
SWITCHC(222, 1:'A', 2:22, 3:'C')==>22
3.3.2. 数值函数
| 函数 | 说明 | 简单示例 | 返回类型 |
| ------------ | ---- | ---------------------------------------- | ---- |
| CEILING() | 向上取整 | CEILING(1.1) CEILING(1.1+2.2) | 数值 |
| FLOORING() | 向下取整 | FLOORING(1.1) FLOORING(1.1+2.2) | 数值 |
| ROUNDING | 四舍五入 | ROUNDING(1.1) ROUNDING(1.1+2.2, 1) | 数值 |
| MAX() | 取最大值 | MAX(1.1, 2, 3) MAX(1.1+2.2, 3, 4) | 数值 |
| MIN() | 取最小值 | MIN(1.1, 2, 3) MIN(1.1+2.2, 3, 4) | 数值 |
| | | | |
CEILING 向上取整
- 一个参数
CEILING(1.1)==>2
CEILING(1.1+2.2)==>4
FLOORING 向下取整
- 一个参数
FLOORING(1.1)==>1
FLOORING(1.1+2.2)==>3
ROUNDING 四舍五入
- 第二个参数可选,表示要四舍五入的小数位数
ROUNDING(1.4)==>1
ROUNDING(1.5)==>2
ROUNDING(1.44, 1)==>1.4
ROUNDING(1.45, 1)==>1.5
MAX 取最大值
- 多个参数,参数之间用半角逗号分隔
MAX(1.1, 2, 3)==>3
MAX(3.3+2.2, 3, 4)==>5.5
MIN 取最小值
- 多个参数,参数之间用半角逗号分隔
MAX(1.1, 2, 3)==>3
MAX(3.3+2.2, 3, 4)==>5.5
3.3.3. 文本函数
| 函数 | 说明 | 简单示例 | 返回类型 |
| ----------- | ---------- | ---------------------------------------- | ---- |
| CONCAT() | 字符串拼接 | CONCAT({A}, 'str') CONCAT({A}, 1, 'str') | 字符串 |
| SUBSTR() | 取子串 | SUBSTR({A}, 1, 2) SWITCH({A}, 0, 2) | 字符串 |
| SUBNUM() | 取字串转数值 | SUBNUM({A}, 1, 2) SUBNUM({A}, 0, 2) | 数值 |
| LEFT() | 从左侧取指定长度子串 | LEFT({OPT:A}, 2) LEFT('123456', 3) | 字符串 |
| RIGHT() | 从右侧取指定长度子串 | RIGHT({OPT:A}, 2) RIGHT('123456', 3) | 字符串 |
| REVERSE() | 反转字符串 | REVERSE({OPT:A}) REVERSE('123456') | 字符串 |
| FIND() | 获取下标 | FIND({OPT:A}, '2') FIND('123456', '23') | 整数 |
| LENGTH() | 获取字符串长度 | LENGTH({OPT:A}) LENGTH('123456') | 整数 |
| | | | |
CONCAT 字符串拼接
- 对所有参数进行字符串方式拼接
CONCAT(1,'23', 4)==>1234
CONCAT('A','BC', 4)==>ABC4
SUBSTR 取子串
- 第二个参数为开始下标(下标从0开始),第三个参数为取串长度(不传时取到尾)
SUBSTR('ABCDE', 0)==>ABCDE
SUBSTR('ABCDE', 0, 3)==>ABC
SUBSTR('ABCDE', 2)==>CDE
SUBSTR('ABCDE', 2, 2)==>CD
SUBNUM 取字串转数值
- 第二个参数为开始下标(下标从0开始),第三个参数为取串长度(不传时取到尾)
SUBNUM('ABC01230321', 3)==>1230321
SUBNUM('ABC01230321', 3, 3)==>12
SUBNUM('ABC01230321', 7, 1)==>0
SUBNUM('ABC01230321', 7, 2)==>3
3.3.4. 逻辑函数
| 函数 | 说明 | 简单示例 | 返回类型 |
| ------------ | ----------- | ---------------------------------------- | ---- |
| NOT() | 逻辑取反 | NOT(true) NOT(true && false) NOT(1 > 2) | 逻辑值 |
| AND() | 逻辑与运算 | AND(true, true, false) AND(1 > 2, 2 > 4, false) | 逻辑值 |
| OR() | 逻辑或运算 | OR(true, true, false) OR(1 > 2, 2 > 4, false) | 逻辑值 |
| IN() | 包含判断 | IN({A}, 1, 2) IN({A}, 1, 2+3) | 逻辑值 |
| HASVALUE() | 是否有数据 | HASVALUE({A}) HASVALUE({B}) | 逻辑值 |
| ISNUMBER() | 是否是数值 | ISNUMBER({A}) ISNUMBER({A}+{B}) | 逻辑值 |
| ISSTART() | 是否以指定字符串开始 | ISSTART({OPT:A}, 'a') ISSTART({OPT:A}, '123') | 逻辑值 |
| ISEND() | 是否以指定字符串结尾 | ISEND({OPT:A}, 'a') ISEND({OPT:A}, '123') | 逻辑值 |
| ISMATCH() | 是否可以用指定正则匹配 | ISMATCH('123456', '^\\d*$') ISMATCH('123456', '^1\\d{5}$') | 逻辑值 |
| | | | |
IN 包含判断
- 判断第一个参数是否在后面的参数中
IN(1,5,4,3,2,1)==>true
IN(1,2,3,4,5)==>false
3.3.5. 参数函数
| 函数 | 说明 | 简单示例 | 返回类型 |
| ------------ | --------- | ---------------------------------------- | -------------------- |
| DATETIME() | 字符串转日期时间 | DATETIME('2021-02-01 12:00') DATETIME('202102011200', 'yyyyMMddHHmm') | 日期 |
| GET() | 获取值或返回默认值 | GET({A}, 'AAA') GET({NUM},123) | 任意值 |
| TONUM() | 转为数值 | TONUM({NUM1}) TONUM('123') | 数值 |
| TOSTR() | 转字符串 | TOSTR({DATE}) TOSTR({DATE}, 'yyyy-MM-dd') | 字符串 |
| META() | 获取参数属性 | META({A}, 'name') META({A}, 'age', 'num') | 字符串或指定类型txt/num/bool |
| DATAMETA() | 获取数据值属性 | DATAMETA({OPT:A}, 'meta03') DATAMETA({OPT:A}, 'meta02', 'bool') | 字符串或指定类型txt/num/bool |
| NOW() | 获取当前系统时间 | NOW() NOW('UTC') | 日期 |
DATETIME 转日期
- 第二个参数为日期格式化模式
日期格式化字符串示例:
yyyy-MM-dd HH:mm:ss
TOSTR 转日期
- 第二个参数为格式化字符串
日期格式化字符串示例:
yyyy-MM-dd HH:mm:ss
NOW 获取当前
Related Skills
node-connect
347.6kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.6kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.6kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
