背景
在短信转发工具TranspondSms中,实现了,单个匹配规则,像这样:
一开始是单个条件的匹配,比如 当手机号是10086就转发 ,后面有用户反馈说有些短信单个条件不能筛选出来,「截图」,像这种情况,当手机号是10086并且内容包含欠费就转发 有群里用户直接说用正则表达式,之前有考虑一下,发现正则表达式对普通用户要求太高,并且不容易实现条件递归嵌套
自由度最高的就是自己实现一个语法集,因为这里的场景很简单,只是对短信进行判断而已,条件很少像手机号短信内容卡槽 并且否或者 开头结尾包含相等 调研了一些语法解析器像 感觉很好用,但是用在这里有点杀鸡用牛刀了,整理了一下要做什么决定手写 首先用户输入或选择规则,如果要使用多级选择框来实现多级嵌套界面有点难搞
交互方案
遂决定直接使用文本框接受用户提交的规则,然后对这些规则一行一行解析,然后组织嵌套关系,最后把要判断的手机号短信内容传进来进行判断
语法设计
接下来就是看怎么定义规则既语法,这里的嵌套情况像这种 当手机号是10086并且(内容包含欠费 或者 内容包含停机) 这里就看怎么表达这种嵌套关系,一种是直接用括号,一种是模仿Python语法,每一行代表一条规则,每一行前面用行首空格代表与上一条规则的关系,比如两行行首都是2个空格表示这两行平级,逐个判断就好,如果第一行0个空格第二行1空格,就代表第二行规则属于第一行规则,他们在一个小括号里,这样就可以表达多个条件的优先级了。
解析
接下来是实现层面的设计,既然每个规则有关联比如下一个规则上一个规则子规则父规则,用一个列表肯定是不行的,用树可以,好,每个节点保存上个节点下个节点父节点子节点,并且保存规则本身像 并且当手机号是10086
接下来是解析每一行 每个关键字用空格隔开,考虑到用户要求匹配的值无法想象,就把末尾的位置就给要求匹配的值,每一行长这个样子 并且 不是 手机号 包含 10086hhchj红红火火恍恍惚惚 这里“包含”空格后面的值直接全部都是用户要求匹配的值,这样就减少解析用户不确定输入的未知风险
首先每一行一个一个字读取,读取有分为几个状态,行首空格阶段:用于记录这一行有几个行首空格,通过对比上个节点的行首空格数来确定和上个节点的关系 接着必须出现 并 或 两个字之一,这时阶段变换行首空格阶段结束,再后面一个字必须是且 者 两个字之一,再后面必须是一个空格,这个阶段是连接词阶段,用来解析出连接词并且或者,如果不满足这个语法直接输出行号并报语法错误:只支持并且或者 之后这个样子依次是确认词阶段,匹配名阶段,匹配值阶段
当各个阶段都顺利完成后,一条规则就生成了
连接
然后通过对比当前规则和前一个规则的行首空格数确认当前规则和前一个规则的关系
最终生成一个规则树:
规则的执行流程:
判定流程
对要判断的短信(包含手机号,短信内容),先执行本节点的规则,如果有子结点(图中虚线指向的节点)就递归合并子结点的规则匹配结果,如果有下一条规则(图中实线箭头指向的节点)就递归合并下一条规则匹配结果;如果最后结果是真就转发这条短信,为假就不转发这条短信。
补充一个完整的流程图: