时下一些产品会搞一些用处不大的功能来提高自己的逼格,而人工智能就成了一柄装逼利器。只要有点发飘的功能,就能冠以人工智能的名头。
之前做过一个产品,需要产品提供语音识别功能,根据用户口令执行相关操作,类似现在的智能音箱,只不过由于产品没有硬件,所以基于应用层的语音唤醒功能很蹩脚,唤醒功能咱先不讨论,那么语音识别功能又如何实现得呢,这个说起来就复杂了,你要先注册科大讯飞账号,然后掏钱,,,,咳咳,,,,,,扯远了,其实语音识别功能就是将用户语音识别成汉字,然后根据汉语日常语法进行解析,解析出高概率的命令,然后反馈给用户来确认,用户确认没问题,那就执行命令。例如我们预备匹配的一些动词(打开,启动,关闭等),以及我们的名词目标(控制面板,首页等),我们解析发现有这些动词名词的组合,然后和用户确认是否执行,否则其他的情况都标识并反馈为 “我没听清,你咬我啊”。
咱们再看看大话设计模式里面的那个例子,如果技术水平发展足够好,我们在未来可以设计出看着乐谱演奏音乐的机器人,它们会根据乐谱的文法规则对乐谱进行解析,并弹奏出美妙的旋律。
然后还有编译器,不同编程语言有不同的编译器,他们会根据语言的文法规则对高级语言进行翻译,翻译成机器可以识别的汇编指令,进一步实现程序的功能。而我们也可以做一个类似的简单编译器,用来将汉语语句或乐谱翻译成高级语言可识别的功能来执行。
其实以上所有例子都涉及到了同一种应用场景,就是需求给定了你一个语言,你要总结或定义出语言的文法,然后针对文法创造出一种解释器,解释给出的语句并执行相应操作,这就是我们所说的解释器模式,而解释器模式在编程中的典型应用就是正则表达式。
解释器模式:
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
我的理解:定义一个语言的文法,并定义一个解释器来解释该语言的句子。
一、名词解释
1、文法,百度连接 https://baike.baidu.com/item/%E6%96%87%E6%B3%95/8974691,其实我觉得就是语法,就是语言的组织规范,就是那些主谓宾定状补,好像啥时候学过。
二、特征
1、文法,我认为的即语法,若对既定语言进行解释翻译,那这个文法就需要咱们学习总结出来,若是自己创建一个语言,那么文法需要自己定义。
2、解释器,提供对语言的专门的解释翻译功能,这使得应用场景客户端不用在关注对语言的解释处理,通过封装实现了解耦,并且解释器可以进一步抽象,以实现文法的变化或增减。
三、作用,个人目前能想到的应用场景就是翻译,对上层的某些语言进行解释。
四、实现
又到了写例子的时候了,思来想去还是实现一个简单的正则表达式功能吧,毕竟很多应用场景里无法充分的展现出非终结符的作用,而正则大家都知道,更好理解一些。
我们把正则简化一些,假设正则里面就只有 [] {} * ? + () 这些文法规则,那么普通字符串就是终结符喽
//上下文
public class Context {
public String regular;
public String data;
}
//公共类
public class LoopResult {
public boolean result;
public int loopMin;
public int loopMax;
public LoopResult(boolean result,int min,int max)
{
this.result = result;
this.loopMin = min;
this.loopMax = max;
}
}
//解析循环次数
public class BasicFunction {
public LoopResult dealLoop(Context loopContext)
{
LoopResult result = new LoopResult(true,1,1);
if(loopContext.regular.startsWith("*"))
{
result.result = true;
result.loopMin = 0;
result.loopMax = -1;
loopContext.regular = loopContext.regular.substring(1);
}
else if(loopContext.regular.startsWith("+"))
{
result.result = true;
result.loopMin = 1;
result.loopMax = -1;
loopContext.regular = loopContext.regular.substring(1);
}
else if(loopContext.regular.startsWith("?"))
{
result.result = true;
result.loopMin = 0;
result.loopMax = 1;
loopContext.regular = loopContext.regular.substring(1);
}
else if(loopContext.regular.startsWith("{"))
{
if(loopContext.regular.indexOf('}') == -1)
{
result.result = false;
}
else
{
String stra = loopContext.regular.substring(0,loopContext.regular.indexOf('}')+1);
loopContext.regular = loopContext.regular.substring(loopContext.regular.indexOf('}')+1);
stra = stra.substring(1,stra.length()-1);
String[] aa = stra.split(",");
//{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
if(aa.length == 1)
{
int nCount = 0;
if(stra.endsWith(","))
{
try
{
nCount = Integer.parseInt(aa[0]);
result.result = true;
result.loopMin = nCount;
result.loopMax = -1;
}
catch (NumberFormatException e)
{
result.result = false;
}
}
else
{
try
{
nCount = Integer.parseInt(aa[0]);
result.result = true;
result.loopMin = nCount;
result.loopMax = nCount;
}
catch (NumberFormatException e)
{
result.result = false;
}
}
}
//{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
else if(aa.length ==2)
{
int nMin = 0,nMax = 0;
try
{
nMin = Integer.parseInt(aa[0]);
nMax = Integer.parseInt(aa[1]);
result.result = true;
result.loopMin = nMin;
result.loopMax = nMax;
}
catch (NumberFormatException e)
{
result.result = false;
}
}
}
}
else
{
}
return result;
}
}
//解释器接口
public abstract class Expression {
//实现对正则表达式的解释
public abstract boolean iterpreter(Context regular);
//实现匹配语句的功能
public abstract boolean match(Context data);
}
//语句规则
public class SentenceExpression extends Expression{
private List<Expression> list;
public SentenceExpression()
{
list = new ArrayList<Expression>();
}
@Override
public boolean iterpreter(Context regular) {
// TODO Auto-generated method stub
System.out.printf("[SentenceExpression::iterpreter] in,data:%s \n",regular.regular);
//语句初始不可能是 * + ? {}
if(regular.regular.startsWith("*")
|| regular.regular.startsWith("+")
|| regular.regular.startsWith("?")
|| regular.regular.startsWith("{") )
return false;
boolean result = true;
while(! regular.regular.isEmpty())
{
//如果为子语句文法规范
if(regular.regular.startsWith("("))
{
if(regular.regular.indexOf(")") > 1)
{
Expression es = new ParenthesesExpression();
if(! es.iterpreter(regular))
{
result = false;
break;
}
list.add(es);
}
else
{
result = false;
break;
}
}
//如果为中括号文法规范
else if(regular.regular.startsWith("["))
{
if(regular.regular.indexOf("]") > 1)
{
Expression es = new BracketExpression();
if(! es.iterpreter(regular))
{
result = false;
break;
}
list.add(es);
}
else
{
result = false;
break;
}
}
//如果为普通字符
else
{
Expression es = new TerminalExpression();
if(! es.iterpreter(regular))
{
result = false;
break;
}
list.add(es);
}
}
return result;
}
@Override
public boolean match(Context data) {
// TODO Auto-generated method stub
System.out.printf("[SentenceExpression::match] in,data:%s \n",data.data);
boolean result = true;
for(int i=0; i<list.size(); i++)
{
Expression ex = list.get(i);
if(! ex.match(data))
{
result = false;
break;
}
}
return result;
}
}
//终结符解释器,对于正则表达式来说,我认为就是普通字符串
public class TerminalExpression extends Expression {
private BasicFunction bf;
private String strData;
private char chLoop;
private int loopMin,loopMax;
public TerminalExpression()
{
bf = new BasicFunction();
strData = new String();
chLoop = 'a';
loopMin = 1;
loopMax = 1;
}
@Override
public boolean iterpreter(Context regular) {
// TODO Auto-generated method stub
System.out.printf("[TerminalExpression::iterpreter] in data:%s \n",regular.regular);
while(! regular.regular.isEmpty())
{
if(regular.regular.startsWith("*")
|| regular.regular.startsWith("+")
|| regular.regular.startsWith("?")
|| regular.regular.startsWith("{")
|| regular.regular.startsWith("[")
|| regular.regular.startsWith("("))
break;
strData = strData.concat(regular.regular.substring(0,1));
regular.regular = regular.regular.substring(1);
}
LoopResult ret = bf.dealLoop(regular);
if(! ret.result) return false;
loopMin = ret.loopMin;
loopMax = ret.loopMax;
chLoop = strData.charAt(strData.length()-1);
strData = strData.substring(0,strData.length()-1);
return true;
}
@Override
public boolean match(Context data) {
// TODO Auto-generated method stub
System.out.printf("[TerminalExpression::match] in,data:%s \n",data.data);
int nCount = 0;
if(! data.data.startsWith(strData))
return false;
data.data = data.data.substring(strData.length());
while(data.data.length() != 0)
{
if(data.data.charAt(0) == chLoop)nCount++;
else break;
data.data = data.data.substring(1);
}
boolean result = false;
if(loopMax < 0)
{
if(nCount >= loopMin) result = true;
else result = false;
}
else
{
if(nCount >= loopMin && nCount <= loopMax) result = true;
else result = false;
}
return result;
}
}
//根据()来解析子表达式语句
public class ParenthesesExpression extends Expression {
private BasicFunction bf;
private int loopMin,loopMax;
private Expression expression;
public ParenthesesExpression()
{
expression = new SentenceExpression();
bf = new BasicFunction();
loopMin = 1;
loopMax = 1;
}
@Override
public boolean iterpreter(Context regular) {
// TODO Auto-generated method stub
System.out.printf("[ParenthesesExpression::iterpreter] in,data:%s \n",regular.regular);
//如果开头结尾是一个(),那么证明是子语句
if(regular.regular.startsWith("("))
{
if(regular.regular.length() <= 2)
return false;
String strPh = regular.regular.substring(1, regular.regular.indexOf(')'));
regular.regular = regular.regular.substring(regular.regular.indexOf(')')+1);
LoopResult ret = bf.dealLoop(regular);
if(! ret.result) return false;
loopMin = ret.loopMin;
loopMax = ret.loopMax;
Context cc = new Context();
cc.regular = strPh;
if(! expression.iterpreter(cc))return false;
}
return true;
}
@Override
public boolean match(Context data) {
// TODO Auto-generated method stub
System.out.printf("[ParenthesesExpression::match] in,data:%s \n",data.data);
int nCount = 0;
while(expression.match(data))
{
nCount++;
}
boolean result = false;
if(loopMax < 0)
{
if(nCount >= loopMin) result = true;
else result = false;
}
else
{
if(nCount >= loopMin && nCount <= loopMax) result = true;
else result = false;
}
return result;
}
}
//[],例如[1-9],表示取任意1到9之间的一个数值(包括1和9)
public class BracketExpression extends Expression {
private BasicFunction bf;
private char chMin,chMax;
private int loopMin,loopMax;
public BracketExpression()
{
bf = new BasicFunction();
chMin = 0;
chMax = 0;
loopMin = 1;
loopMax = 1;
}
@Override
public boolean iterpreter(Context regular) {
System.out.printf("[BracketExpression::iterpreter] in,data:%s \n",regular.regular);
// TODO Auto-generated method stub
String strRe = regular.regular.substring(0,regular.regular.indexOf("]")+1);
strRe = strRe.substring(1,strRe.length()-1);
String[] aa = strRe.split("-");
if(aa.length != 2)return false;
if(aa[0].length()!=1 || aa[1].length()!=1 ) return false;
chMin = aa[0].charAt(0);
chMax = aa[1].charAt(0);
regular.regular = regular.regular.substring(regular.regular.indexOf("]")+1);
LoopResult ret = bf.dealLoop(regular);
if(! ret.result) return false;
loopMin = ret.loopMin;
loopMax = ret.loopMax;
return true;
}
@Override
public boolean match(Context data) {
// TODO Auto-generated method stub
System.out.printf("[BracketExpression::match] in,data:%s \n",data.data);
int nCount = 0;
while(data.data.charAt(0)>=chMin && data.data.charAt(0)<= chMax)
{
nCount++;
data.data = data.data.substring(1);
}
boolean result = false;
if(loopMax < 0)
{
if(nCount >= loopMin) result = true;
else result = false;
}
else
{
if(nCount >= loopMin && nCount <= loopMax) result = true;
else result = false;
}
return result;
}
}
//应用场景
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
// [] {} * ? + ()
Context context = new Context();
context.regular = "abc*[d-g]?([h-n]{1,9}opqrst)uvwxyz+";
context.data = "ablopqrstuvwxyz";
Expression exp = new SentenceExpression();
if(! exp.iterpreter(context))
{
System.out.println("mother fuck!");
return:
}
else
{
System.out.println("yes baby!");
}
if(! exp.match(context))
{
System.out.println("mother fuck!");
}
else
{
System.out.println("yes baby!");
}
}
}
给出的例子是为了阐述解释器模式的使用方法,代码存在很多漏洞,不可以仔细推敲,如果您发现了代码的漏洞想找我理论,哈哈,怎么可能,我不会留联系方式的。