-
Notifications
You must be signed in to change notification settings - Fork 18
[zh_CN]IParser Configuration
为了保证在 Yacep 分析的结果在转换为可执行代码时尽量少出现一些问题, ReadOnlyParseOption 对象一旦创建,其内部的属性都是只读的。
只读配置对象 ReadOnlyParseOption 为 IParser 提供了在分析解析字符串所需的全部配置, 配置大致分为三类。
ParseOption 为辅助构建 ReadOnlyParseOption 而添加的一个类。而 ParseOptionExtension 为辅助构建 ParseOption 而添加的一个类。
通常的用法是使用 new 操作或 ParseOption.CreateOption 方法创建一个新的 ParseOption 对象,然后通过 ParseOptionExtension 的扩展方法为 ParseOption 设置配置值,最后调用 AsReadOnly 方法来构建一个只读的配置 ReadOnlyParseOption 。
- 示例代码:构建和使用 ReadOnlyParseOption
var option = new ParseOption()
.NotAllowedArrayExpression() //不允许分析包含数组表达式的字符串
.NotAllowedInExpression() //不允许分析包含In表达式的字符串
.AddLiteralValue("one_hundred", 100) //添加字面值oneHundred,代表数字100
.AddLiteralValue("two_thousand", 2000) //添加字面值twoThousand,代表数字2000
.AddLiteralValue("two_thousand_and_one", 2100) //添加字面值twoThousand,代表数字2000
.AddBinaryOperator("plus", (a, b) => (int)a + (int)b, 2) //添加二元操作符plus,优先级为2
.AddBinaryOperator("is", (a, b) => (int)a == (int)b, 1) //添加二元操作符is,优先级为1,数字越小优先级越低
.AsReadOnly();
Console.WriteLine("100 plus 2000 is 2100".Compile(option).EvaluateAs<bool>());//true
Console.WriteLine("one_hundred plus two_thousand is two_thousand_and_one".Compile(option).EvaluateAs<bool>());//true
Console.WriteLine("one_hundred plus two_thousand is 2100".Compile(option).EvaluateAs<bool>());//true
禁止能力是禁止 Yacep 对一些特征字符串处理能力。在遇到特征字符串时,Yacep 将会报错处理。
-
不允许分析包含数组表达式的字符串,如果字符串中包含数组表达式将会抛出异常。
"[1, 2]".ToEvaluableExpression(new ParseOption()
.NotAllowedArrayExpression()
.AsReadOnly());
//TupacAmaru.Yacep.Exceptions.ParseException:"Array expression is not allowed at character 0"
-
不允许分析包含条件表达式的字符串,如果字符串中包含条件表达式将会抛出异常。
"true ? 1 : 2".ToEvaluableExpression(new ParseOption()
.NotAllowedConditionExpression()
.AsReadOnly());
//TupacAmaru.Yacep.Exceptions.ParseException:"Condition expression is not allowed at character 0"
-
不允许分析包含对象成员表达式的字符串,如果字符串中包含对象成员表达式将会抛出异常。
"m.Length".ToEvaluableExpression(new ParseOption()
.NotAllowedMemberExpression()
.AsReadOnly());
//TupacAmaru.Yacep.Exceptions.ParseException:"Member expression is not allowed at character 1"
- 不允许分析包含索引表达式的字符串,如果字符串中包含索引表达式将会抛出异常。
"m[0]".ToEvaluableExpression(new ParseOption()
.NotAllowedIndexerExpression()
.AsReadOnly());
//TupacAmaru.Yacep.Exceptions.ParseException:"Indexer expression is not allowed at character 1"
"m['Length']".ToEvaluableExpression(new ParseOption()
.NotAllowedIndexerExpression()
.AsReadOnly());
//TupacAmaru.Yacep.Exceptions.ParseException:"Indexer expression is not allowed at character 1"
不允许分析包含In表达式的字符串,如果字符串中包含In表达式将会抛出异常。
"1 in (1, 2, 3)".ToEvaluableExpression(new ParseOption()
.NotAllowedInExpression()
.AsReadOnly());
//TupacAmaru.Yacep.Exceptions.ParseException:"In expression is not allowed at character 5"
在 Yacep 中是没有带符号数字的,因为符号 -
可以被重定义为其他意义. 但是为了方便广大C#开发者的使用习惯,内部会按照值的大小在读取的时候动态转换类型. 如果一个整数大于 4294967295 会被读取为 ulong
类型,如果还大于 2147483648 就会被读取为 integer
类型,否则就会读取为 int
类型. 如果禁用数值转换,Yacep会将读取到数值统一按照ulong类型处理。
数值类型 | C#值类型 | 描述 |
---|---|---|
ulong | UInt64 | 如果一个整数大于 4294967295 会被读取为 ulong 类型. |
integer | UInt32 | 如果还大于 2147483648 就会被读取为 integer
|
int | Int32 | 小于 2147483648 的数值 |
decimal | Decimal | 十进制浮点数 |
此功能的实现代码:Parser.cs#L66
Console.WriteLine("111".Compile().EvaluateAs<object>().GetType()); //System.Int32
Console.WriteLine("111".Compile(new ParseOption()
.NotAllowedConvertUnsignedInteger()
.AsReadOnly())
.EvaluateAs<object>()
.GetType()); //System.UInt64
字面值 | 释义 |
---|---|
true | Bool值true |
false | Bool值false |
null | null |
Yacep 支持将内置的三个字面量清除掉
使用new方法创建的ParseOption会不带任何内置字面量, 在调用 ParseOption.CreateOption 方法的时候设置参数 addDefaultLiteralValues
为 false
则不会添加任何内置字面量
自定义字面量 代码
重要!!! 字面量不能包含空格,字面量的值不能是委托类型. 在使用字面量时, Yacep 区分大小写. 所以字面量true
和True
可以定义为两个不同字面量.
- 添加符号为字面量
Console.WriteLine("π".Compile(new ParseOption()
.AddLiteralValue("π", Math.PI) //数值π
.AsReadOnly())
.EvaluateAs<double>()); //3.14159265358979
- 添加字符为字面量
Console.WriteLine("T".Compile(new ParseOption()
.AddLiteralValue("T", "T is a very long string") //长字符串
.AsReadOnly())
.EvaluateAs<string>()); //T is a very long string
- 添加字符串为字面量
Console.WriteLine("os_version".Compile(new ParseOption()
.AddLiteralValue("os_version", Environment.OSVersion.Version) //操作系统版本
.AsReadOnly())
.EvaluateAs<Version>()); //10.0.18362.0
符号 | 释义 | 操作 |
---|---|---|
+ | 正号 | 表示数学中的正号 + |
- | 负号 | 表示数学中的负号 - |
! | 非 | 表示一个非操作,返回一个bool值 |
注意:Yacep 中,小于等于0的数,空字符串以及为null的对象在转换为bool值的时候等于false。大于0的数,不为空的字符串,不为null的对象,在转换为bool值的时候等于true
- 示例代码:使用默认配置获取抽象语法树 代码
//代码使用了Yacep内的扩展方法,Yacep所有的扩展方法都在命名空间TupacAmaru.Yacep.Extensions下
Console.WriteLine("+m".Compile().Evaluate(new { m = 12 }));//12
Console.WriteLine("-m".Compile().Evaluate(new { m = 12 }));//-12
Console.WriteLine("!m".Compile().Evaluate(new { m = 12 }));//False
Yacep 支持将内置的3个一元操作符清除掉
使用new方法创建的ParseOption会不带任何内置一元操作符, 在调用 ParseOption.CreateOption 方法的时候设置参数 addDefaultUnaryOperators
为 false
则不会添加任何内置一元操作符
自定义一元操作符 代码
重要!!! 一元操作符不能包含空格. 在使用一元操作符时, Yacep 区分大小写.
- 添加符号为一元操作符
var option = new ParseOption()
.AddUnaryOperator("#", value => (value as string)?.Length ?? 0) //获取字符串长度
.AsReadOnly();
Console.WriteLine("#'hello'".Compile(option).EvaluateAs<int>()); //5
- 添加字符为一元操作符
var option = new ParseOption()
.AddUnaryOperator("L", value => (value as string)?.Length ?? 0) //获取字符串长度
.AsReadOnly();
Console.WriteLine("L'hello'".Compile(option).EvaluateAs<int>()); //5
-
添加字符串为一元操作符(不推荐)
不推荐添加字符串为一元操作符,这种情况会降低表达式的可读性,推荐使用自定义函数
var option = new ParseOption()
.AddUnaryOperator("LengthOf", value => (value as string)?.Length ?? 0) //获取字符串长度
.AsReadOnly();
Console.WriteLine("LengthOf'hello'".Compile(option).EvaluateAs<int>()); //5
重要!!! Yacep 中,小于等于0的数,空字符串以及为null的对象在转换为bool值的时候等于false
。大于0的数,不为空的字符串,不为null的对象,在转换为bool值的时候等于true
,以下二元操作符中的或和与操作,都会按照这个规则转换。
符号 | 释义 | 操作 | 优先级 |
---|---|---|---|
|| | 或, | 或操作 | 1 |
&& | 与 | 与操作 | 2 |
== | 相等判定 | 相等运算符 | 3 |
!= | 不相等判定 | 不相等运算符 | 3 |
< | 小于判定 | 小于运算符 | 4 |
> | 大于判定 | 大于运算符 | 4 |
<= | 小于等于判定 | 小于等于运算符 | 4 |
>= | 大于等于判定 | 小于等于运算符 | 4 |
+ | 加运算符,支持数值与数值相加 也支持字符串相加 |
加运算符 | 5 |
- | 减运算符 | 减运算符 | 5 |
* | 乘运算符,支持数值与数值相乘 也支持字符串与数值相乘(表重复字符串的次数) |
乘运算符 | 6 |
/ | 除运算符 | 除运算符 | 6 |
% | 求余运算符 | 求余运算符 | 6 |
Yacep 支持将内置的13个二元操作符清除掉
使用new方法创建的ParseOption会不带任何内置一元操作符, 在调用 ParseOption.CreateOption 方法的时候设置参数 addDefaultBinaryOperators
为 false
则不会添加任何内置一元操作符
自定义二元操作符 代码
重要!!! 二元操作符不能包含空格, 且in作为内置的表达式类型不能被重新定义为二元操作符. 在使用二元操作符时, Yacep 区分大小写.
- 添加符号为二元操作符
Console.WriteLine("'b'@'abc'".Compile(new ParseOption()
.AddBinaryOperator("@", (a, b) => (b as string)?.IndexOf(a as string) ?? 0, 10) //获取子串位置
.AsReadOnly())
.EvaluateAs<double>()); //1
- 添加字符为二元操作符
Console.WriteLine("'b'I'abc'".Compile(new ParseOption()
.AddBinaryOperator("I", (a, b) => (b as string)?.IndexOf(a as string) ?? 0, 10) //获取子串位置
.AsReadOnly())
.EvaluateAs<double>()); //1
- 添加字符串为二元操作符
Console.WriteLine("'hello' concat 'world'".Compile(new ParseOption()
.AddBinaryOperator("concat", (a, b) => $"{a}, {b}", 10) //连接字符串
.AsReadOnly())
.EvaluateAs<string>()); //hello, world
Yacep 内置了两类函数, 一类是统计类函数( 实现代码 ), 一类是日期类函数( 实现代码 )
5个统计类函数 实现代码
函数 | 释义 | 操作 |
---|---|---|
len | 取长度 | 获取集合的长度 |
max | 最大值 | 求一个数值数组中最大的值 |
min | 最小值 | 求一个数值数组中最小的值 |
sum | 求和 | 求一个数值数组的和 |
avg | 均值 | 求一个数值数组的均值 |
9个日期类函数 实现代码
函数 | 释义 | 操作 | 返回值类型 |
---|---|---|---|
now | 获取当前日期及时间 | 默认的格式为yyyy/MM/dd HH:mm:ss
|
字符串 |
today | 获取当前日期 | 默认的格式为yyyy/MM/dd
|
字符串 |
time | 获取当前时间 | 默认的格式为HH:mm:ss
|
字符串 |
year | 获取当前年的数值 | 等同于DateTime.Now.Year
|
数值 |
month | 获取当前月的数值 | 等同于DateTime.Now.Month
|
数值 |
day | 获取当前日的数值 | 等同于DateTime.Now.Day
|
数值 |
hour | 获取当前小时的数值 | 等同于DateTime.Now.Hour
|
数值 |
minute | 获取当前分钟的数值 | 等同于DateTime.Now.Minute
|
数值 |
second | 获取当前秒的数值 | 等同于DateTime.Now.Second
|
数值 |
Yacep 支持将内置的14个二元操作符清除掉
使用new方法创建的ParseOption会不带任何内置一元操作符, 在调用 ParseOption.CreateOption 方法的时候设置参数 addStatisticsFunctions
为 false
则不会添加任何内置的统计类函数,设置参数 addDateAndTimeFunctions
为 false
则不会添加任何内置的日期类函数
自定义函数 代码
重要!!! 函数名不能包含空格, 且in作为内置的表达式类型不能被重新定义为函数. 在调用函数时, Yacep 区分大小写.
- 添加符号为函数
Console.WriteLine("$('body')".Compile(new ParseOption()
.AddNakedFunction("$", values => $"find {values[0]} in dom") //拼接字符串
.AsReadOnly())
.EvaluateAs<string>()); //find body in dom
- 添加字符为二元操作符
Console.WriteLine("J('body')".Compile(new ParseOption()
.AddNakedFunction("J", values => $"find {values[0]} in dom") //拼接字符串
.AsReadOnly())
.EvaluateAs<string>()); //find body in dom
- 添加字符串为二元操作符
Console.WriteLine("jQuery('body')".Compile(new ParseOption()
.AddNakedFunction("jQuery", values => $"find {values[0]} in dom") //拼接字符串
.AsReadOnly())
.EvaluateAs<string>()); //find body in dom
Yacep : yet another csharp expression parser