Created
December 22, 2019 18:22
-
-
Save liyonghelpme/7a8d89ba40b5bae4f3c63b8d32cb6034 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//digitSeq e digit | |
enum NodeType { | |
Enter, | |
Digit, | |
Exponent, | |
End, | |
BeforePoint, | |
Point, | |
AfterPoint, | |
} | |
enum TokenType { | |
Num, | |
Sign, | |
Point, | |
Exp, | |
Empty, | |
Unknown, | |
EOF, //读取结束状态 | |
} | |
enum ParseResult { | |
OK, | |
Error, | |
} | |
class Result { | |
ret : ParseResult = null | |
nextToken : number = null | |
reason : string = null | |
} | |
let list = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] | |
//0-9 | |
function IsNumber(c : string){ | |
// return !isNaN(Number(c)) | |
for(let i = 0; i < list.length; i++){ | |
if(list[i] === c) return true | |
} | |
return false | |
} | |
function IsSign(c : string) { | |
return c == "-" || c == "+" | |
} | |
function IsPoint(c : string) { | |
return c == "." | |
} | |
function IsE(c : string) { | |
return c == "e" | |
} | |
function IsEmpty(c : string) { | |
return c == " " || c == "\t" | |
} | |
function GetTokenType(c : string) { | |
if(IsNumber(c)) return TokenType.Num | |
if(IsSign(c)) return TokenType.Sign | |
if(IsE(c)) return TokenType.Exp | |
if(IsPoint(c)) return TokenType.Point | |
if(IsEmpty(c)) return TokenType.Empty | |
return TokenType.Unknown | |
} | |
class StateMachine { | |
curNode : StateNode | |
curStep : number = 0 | |
input : string = null | |
result : boolean | |
allNodes : Map<NodeType, StateNode> = new Map() | |
Init() {} | |
// MoveNext() { | |
// if(this.curNode.next != null){ | |
// this.curNode = this.curNode.next | |
// }else { | |
// console.log("Error:NoNext:", ) | |
// } | |
// } | |
MoveTo(s : StateNode) { | |
this.curNode = s | |
} | |
Parse(inp : string) { | |
inp += " " | |
this.input = inp | |
// console.log("parse", this.input) | |
for(this.curStep = 0; this.curStep < this.input.length;){ | |
// console.log(this.curNode, this.curStep) | |
let ret = this.curNode.Read(this.input, this.curStep) | |
// console.log(this.curNode.type, this.curNode.constructor.name, ret) | |
if(ret.ret == ParseResult.Error) { | |
// console.log(ret.reason, this.curStep) | |
// console.log(this.curNode.constructor.name) | |
return false | |
} | |
this.curStep = ret.nextToken | |
} | |
if(this.curNode.type != NodeType.End){ | |
// console.log("not find number") | |
return false | |
} | |
return true | |
} | |
MoveToType(nt : NodeType) { | |
this.curNode = this.allNodes.get(nt) | |
} | |
AddNode(s : StateNode) { | |
this.allNodes.set(s.type, s) | |
s.mac = this | |
} | |
GetNode( t : NodeType) | |
{ | |
return this.allNodes.get(t) | |
} | |
} | |
class StateNode { | |
type : NodeType = null | |
// next : StateNode = null | |
mac : StateMachine = null | |
// subNodes : Map<NodeType, StateNode> = new Map() | |
parent : StateNode | |
constructor(machine : StateMachine) { | |
this.mac = machine | |
} | |
Read(input :string, i : number){ | |
let ret = new Result() | |
ret.nextToken = i | |
ret.ret = ParseResult.OK | |
return ret | |
} | |
// AddChild(s : StateNode){ | |
// this.subNodes.set(s.type, s) | |
// s.parent = this | |
// s.mac = this.mac | |
// } | |
// GetChild(nt : NodeType) { | |
// return this.subNodes.get(nt) | |
// } | |
} | |
class EnterNode extends StateNode { | |
Read(input :string, i : number) { | |
let c = input[i] | |
let tk = GetTokenType(c) | |
let ret = new Result() | |
// console.log("Enter", c, tk) | |
switch(tk) { | |
case TokenType.Empty: | |
ret.nextToken = i+1 | |
ret.ret = ParseResult.OK | |
return ret | |
case TokenType.Sign: | |
case TokenType.Num: | |
case TokenType.Point: | |
this.mac.MoveToType(NodeType.Digit) | |
ret.nextToken = i | |
ret.ret = ParseResult.OK | |
return ret | |
case TokenType.Exp: | |
default: | |
ret.nextToken = 0 | |
ret.ret = ParseResult.Error | |
ret.reason = "exp or unknown token" | |
return ret | |
} | |
} | |
} | |
class BeforePoint extends StateNode { | |
hasSign : boolean = false | |
readNum : string[] = [] | |
firstNum : number = null | |
numCount : number = 0 | |
Read(input :string, i : number){ | |
let ret = new Result() | |
let c = input[i] | |
switch(GetTokenType(c)){ | |
case TokenType.Sign: | |
if(this.readNum.length > 0) { | |
ret.ret = ParseResult.Error | |
ret.reason = "Read Sign" | |
return ret | |
} | |
this.hasSign = true | |
this.readNum.push(c) | |
ret.ret = ParseResult.OK | |
ret.nextToken = i+1 | |
return ret | |
case TokenType.Num: | |
this.readNum.push(c) | |
ret.ret = ParseResult.OK | |
ret.nextToken = i+1 | |
if(this.firstNum == null){ | |
this.firstNum = Number(c) | |
} | |
this.numCount++ | |
// if(this.firstNum == 0 && this.numCount > 1) { | |
// ret.ret = ParseResult.Error | |
// ret.reason = "first zero" | |
// return ret | |
// } | |
return ret | |
case TokenType.Point: | |
//检查数字完整性 | |
// if(this.readNum.length > 0) { | |
// if(this.numCount > 1 && this.firstNum == 0){ | |
// ret.ret = ParseResult.Error | |
// ret.reason = "first Zero" | |
// return ret | |
// } | |
// } | |
ret.ret = ParseResult.OK | |
ret.nextToken = i | |
// this.mac.MoveTo(this.parent.GetChild(NodeType.Point)) | |
this.mac.MoveToType(NodeType.Point) | |
return ret | |
// if(this.readNum.length) | |
case TokenType.Exp: | |
if(this.numCount == 0){ | |
ret.reason = "No Number" | |
ret.ret = ParseResult.Error | |
return ret | |
} | |
this.mac.MoveToType(NodeType.Exponent) | |
ret.ret = ParseResult.OK | |
ret.nextToken = i+1 | |
return ret | |
//读取结束 | |
case TokenType.Empty: | |
// if(this.readNum.length == 0){ | |
// ret.reason = "Error No Num" | |
// ret.ret = ParseResult.Error | |
// return ret | |
// } | |
// if(this.readNum.length == 1 && this.hasSign){ | |
// ret.reason = "Error No Num" | |
// ret.ret = ParseResult.Error | |
// return ret | |
// } | |
if(this.numCount == 0) { | |
ret.reason = "Error No Num" | |
ret.ret = ParseResult.Error | |
return ret | |
} | |
// if(this.numCount > 1 && this.firstNum == 0){ | |
// ret.ret = ParseResult.Error | |
// ret.reason = "first Zero" | |
// return ret | |
// } | |
ret.ret = ParseResult.OK | |
ret.nextToken = i+1 | |
this.mac.MoveToType(NodeType.End) | |
return ret | |
default: | |
ret.reason = "Error Token" | |
ret.ret = ParseResult.Error | |
return ret | |
} | |
} | |
} | |
class PointNode extends StateNode { | |
hasPoint : boolean = false | |
Read(input :string, i : number){ | |
let ret = new Result() | |
let c = input[i] | |
switch(GetTokenType(c)){ | |
case TokenType.Point: | |
this.hasPoint = true | |
ret.ret = ParseResult.OK | |
ret.nextToken = i+1 | |
this.mac.MoveToType(NodeType.AfterPoint) | |
return ret | |
default: | |
ret.ret = ParseResult.Error | |
ret.reason = "Not Find Point" | |
return ret | |
} | |
} | |
} | |
class AfterNode extends StateNode { | |
nums : number[] = [] | |
numCount : number = 0 | |
Read(input :string, i : number){ | |
let ret = new Result() | |
let c = input[i] | |
switch(GetTokenType(c)){ | |
case TokenType.Num: | |
ret.ret = ParseResult.OK | |
ret.nextToken = i+1 | |
this.nums.push(Number(c)) | |
this.numCount++ | |
return ret | |
case TokenType.Exp: { | |
let bt = this.mac.GetNode(NodeType.BeforePoint) as BeforePoint | |
if(bt.numCount == 0 && this.numCount == 0) { | |
ret.ret = ParseResult.Error | |
ret.reason = "no numb" | |
return ret | |
} | |
ret.ret = ParseResult.OK | |
ret.nextToken = i+1 | |
this.mac.MoveToType(NodeType.Exponent) | |
return ret | |
} | |
case TokenType.Empty: { | |
let bt = this.mac.GetNode(NodeType.BeforePoint) as BeforePoint | |
if(bt.numCount == 0 && this.numCount == 0) { | |
ret.ret = ParseResult.Error | |
ret.reason = "no numb" | |
return ret | |
} | |
ret.ret = ParseResult.OK | |
ret.nextToken = i+1 | |
this.mac.MoveToType(NodeType.End) | |
return ret | |
} | |
default: | |
ret.ret = ParseResult.Error | |
ret.reason = "Error Token" | |
return ret | |
} | |
} | |
} | |
//digit Exp | |
//Sign number point number | |
class DigitNode extends StateNode { | |
Read(input :string, i : number){ | |
let ret = new Result() | |
let c = input[i] | |
switch(GetTokenType(c)){ | |
case TokenType.Num: | |
case TokenType.Sign: | |
// this.mac.MoveTo(this.GetChild(NodeType.BeforePoint)) | |
this.mac.MoveToType(NodeType.BeforePoint) | |
ret.nextToken = i | |
ret.ret = ParseResult.OK | |
return ret | |
case TokenType.Point: | |
// this.mac.MoveTo(this.GetChild(NodeType.Point)) | |
this.mac.MoveToType(NodeType.Point) | |
ret.nextToken = i | |
ret.ret = ParseResult.OK | |
return ret | |
case TokenType.Exp: | |
case TokenType.Empty: | |
default: | |
ret.ret = ParseResult.Error | |
ret.reason = "Empty" | |
return ret | |
} | |
} | |
} | |
class ExponentNode extends StateNode { | |
hasSign : boolean | |
nums : string[] = [] | |
numCount : number = 0 | |
Read(input :string, i : number){ | |
let ret = new Result() | |
let c = input[i] | |
switch(GetTokenType(c)){ | |
case TokenType.Sign: | |
if(this.nums.length > 0) { | |
ret.reason = "sign error" | |
ret.ret = ParseResult.Error | |
return ret | |
} | |
this.hasSign = true | |
this.nums.push(c) | |
ret.nextToken = i+1 | |
ret.ret = ParseResult.OK | |
return ret | |
case TokenType.Num: | |
this.nums.push(c) | |
ret.nextToken = i+1 | |
ret.ret = ParseResult.OK | |
this.numCount++ | |
return ret | |
case TokenType.Empty: | |
if(this.numCount == 0) { | |
ret.ret = ParseResult.Error | |
ret.reason = "NO Number" | |
return ret | |
} | |
this.mac.MoveToType(NodeType.End) | |
ret.nextToken = i+1 | |
ret.ret = ParseResult.OK | |
return ret | |
default: | |
ret.reason = "token error" | |
ret.ret = ParseResult.Error | |
return ret | |
} | |
} | |
} | |
class EndNode extends StateNode { | |
Read(input :string, i : number){ | |
let ret = new Result() | |
let c = input[i] | |
switch(GetTokenType(c)){ | |
case TokenType.Empty: | |
ret.nextToken = i+1 | |
ret.ret = ParseResult.OK | |
return ret | |
default: | |
ret.reason = "error token" | |
ret.ret = ParseResult.Error | |
return ret | |
} | |
} | |
} | |
//浮点数判定Node | |
class FloatMachine extends StateMachine { | |
Init() { | |
let n = new EnterNode(this) | |
n.type = NodeType.Enter | |
this.curNode = n | |
let n1 = new DigitNode(this) | |
n1.type = NodeType.Digit | |
let n3 = new BeforePoint(this) | |
n3.type = NodeType.BeforePoint | |
// n1.AddChild(n3) | |
let n4 = new PointNode(this) | |
n4.type = NodeType.Point | |
// n1.AddChild(n4) | |
let n5 = new AfterNode(this) | |
n5.type = NodeType.AfterPoint | |
// n1.AddChild(n5) | |
let n2 = new ExponentNode(this) | |
n2.type = NodeType.Exponent | |
// n3.next = n4 | |
// n4.next = n5 | |
// n5.next = n2 | |
// n.next = n1 | |
// n1.next = n2 | |
let n6 = new EndNode(this) | |
n6.type = NodeType.End | |
this.AddNode(n1) | |
this.AddNode(n2) | |
this.AddNode(n3) | |
this.AddNode(n4) | |
this.AddNode(n5) | |
this.AddNode(n6) | |
} | |
} | |
class CheckNum { | |
input : string | |
Check() { | |
let m = new FloatMachine() | |
m.Init() | |
return m.Parse(this.input) | |
} | |
} | |
var test = [ | |
// "0", | |
// " 0.1 ", | |
// "abc" , | |
// "1 a" , | |
// "2e10" , | |
// " -90e3 " , | |
// " 1e", | |
// "e3" , | |
// " 6e-1" , | |
// " 99e2.5 " , | |
// "53.5e93", | |
// " --6 " , | |
// "-+3" , | |
// "95a54e53" , | |
".", | |
"01", | |
] | |
test.forEach(element => { | |
var ip = element | |
var cn = new CheckNum() | |
cn.input = ip | |
console.log(ip, cn.Check()) | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment