Created
February 8, 2022 05:40
-
-
Save ikasoba/b95e6b87bbdaf22e61f73d7c07cc0a31 to your computer and use it in GitHub Desktop.
順序あり(多分)、正負の数値(実数あり)の計算式を計算するJavaScriptの関数
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
| const calc=((raw)=>{ | |
| const sw = (addIndex,v,f)=>new class { | |
| cases=new Map(); | |
| def=null; | |
| c(v,f){ | |
| this.cases.set(v,f) | |
| return this | |
| } | |
| d(f){ | |
| this.def=f | |
| return this | |
| } | |
| eval(_f=()=>{}){ | |
| _f(this,v) | |
| for (const [k,f] of this.cases.entries()){ | |
| let r; | |
| if ((typeof k == "string" && v.startsWith(k)) || (k instanceof RegExp && (r=v.match(k)))){ | |
| addIndex(k.length!=null ? k.length : r[0]?.length) | |
| return f(r) | |
| } | |
| } | |
| if (this.def)return this.def(v) | |
| } | |
| }().eval(f); | |
| class Group extends Array { | |
| constructor(...iterable){ | |
| super(...iterable) | |
| } | |
| setPriority(priority=0){ | |
| this.priority=priority | |
| return this | |
| } | |
| } | |
| let tkns=[] | |
| let bracketLev=0 | |
| for (let i=0;i<raw.length;){ | |
| const t=sw((v)=>i+=v,raw.slice(i),(s)=> | |
| s.c(/^-?(?:[1-9][0-9]+|[0-9])(?:\.[0-9]+)?/,(v)=>parseFloat(v[0])) | |
| .c(/^[+\-*/^%]/,(v)=>v[0]) | |
| .c("(",()=>{bracketLev++;return "("}) | |
| .c(")",()=>{bracketLev--;return ")"}) | |
| .d((v)=>{throw new Error(`invalid character ${v[0]}`)}) | |
| ) | |
| if (t)tkns.push(t) | |
| } | |
| function generateGroupFromBrackets(tkns){ | |
| let currentBracketLev=null | |
| let currentBracketStart=null | |
| let bracketLev=0 | |
| for (let i=0;i<tkns.length;i++){ | |
| if (tkns[i]=="("){ | |
| if (currentBracketLev==null){ | |
| currentBracketLev=bracketLev | |
| currentBracketStart=i | |
| } | |
| bracketLev++ | |
| }else if (tkns[i]==")"){ | |
| bracketLev-- | |
| if (currentBracketLev!=null && currentBracketLev==bracketLev){ | |
| return tkns.slice(0,currentBracketStart) | |
| .concat( | |
| [new Group(...generateGroupFromBrackets(tkns.slice(currentBracketStart+1,i))).setPriority(2)], | |
| ) | |
| .concat( | |
| tkns.slice(i+1) | |
| ) | |
| } | |
| } | |
| } | |
| return tkns | |
| } | |
| function generateGroupFromBinOps(tkns,nested=0){ | |
| for (let i=0;i<tkns.length;i++){ | |
| if (tkns[i] instanceof Array){ | |
| tkns[i]=generateGroupFromBinOps(tkns[i]) | |
| continue | |
| } | |
| } | |
| if (nested)return tkns; | |
| for (const o of [["^"],["*","/","%"],["+","-"]]){ | |
| for (let i=0;i<tkns.length;i++){ | |
| if (tkns[i] instanceof Array)continue; | |
| if (o.some(o=>tkns[i]==o)){ | |
| console.log(tkns.slice(i-1,i+2)) | |
| return tkns.slice(0,i-1) | |
| .concat( | |
| [new Group(...generateGroupFromBinOps(tkns.slice(i-1,i+2),1)).setPriority(0+(o=="^"))] | |
| ) | |
| .concat( | |
| tkns.slice(i+2) | |
| ) | |
| } | |
| } | |
| } | |
| return tkns | |
| } | |
| function generateGroups(tkns){ | |
| return generateGroupFromBinOps(generateGroupFromBrackets(tkns)) | |
| } | |
| const tree=generateGroups(tkns) | |
| if (bracketLev)throw new Error("Parentheses are not closed") | |
| const stack=[] | |
| const findGroup=()=>{} | |
| const evaluate = (tree)=>{ | |
| if (typeof tree == "number")return tree; | |
| for (let i=0;i<tree.length;i++){ | |
| if (tree[i] instanceof Array){ | |
| stack.push(evaluate(tree[i])) | |
| continue | |
| } | |
| if (typeof tree[i] == "number")stack.push(tree[i]); | |
| else if (tree[i]=="^")stack.push(stack.pop()**evaluate(tree[i+=1])); | |
| else if (tree[i]=="*")stack.push(stack.pop()*evaluate(tree[i+=1])); | |
| else if (tree[i]=="/")stack.push(stack.pop()/evaluate(tree[i+=1])); | |
| else if (tree[i]=="%")stack.push(stack.pop()%evaluate(tree[i+=1])); | |
| else if (tree[i]=="+")stack.push(stack.pop()+evaluate(tree[i+=1])); | |
| else if (tree[i]=="-")stack.push(stack.pop()-evaluate(tree[i+=1])); | |
| } | |
| return stack.pop() | |
| } | |
| return evaluate(tree) | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment