使用方法
開啟Ocaml
複製下面的code
接著輸入
startSimplize 字串
即可處理
ex
# startSimplize "x+y+2*3+2x+x^2+y^2";;
- : string = "x^2+3x+y^2+y+6"
| type bitree = Leaf of int array | Node of string * bitree * bitree | Empty | |
| exception Oops | |
| exception WrongType | |
| (*Julia's code*) | |
| let left = function Node (x, y, z) -> y | |
| let right = function Node (x, y, z) -> z | |
| (* let getVal a = match a with | |
| Node (x, y, z) -> x | |
| | Leaf (w) -> w *) | |
| let getType a = match a with | |
| "+" -> "operator" | |
| | "-" -> "operator" | |
| | "*" -> "operator" | |
| | "/" -> "operator" | |
| | "^" -> "power" | |
| | "(" -> "parenthese" | |
| | ")" -> "parenthese" | |
| | _ -> try if int_of_string a = 123 then "number" | |
| else "number" with Failure "int_of_string" -> "variable" (* include both single variable ex. x, y AND compound variable ex. x^2, y^3 *) | |
| let explode s = | |
| let rec exp i l t c = | |
| if i < 0 then | |
| if t = "" then l | |
| else if c = true then t::l | |
| else t :: "*" :: l | |
| else if (Char.escaped s.[i]) = " " then exp (i - 1) l t c | |
| else if getType (Char.escaped s.[i]) = "operator" then | |
| if t = "" then exp (i - 1) ((Char.escaped s.[i]) :: l) "" true | |
| else if c = true then exp (i - 1) ((Char.escaped s.[i]) :: (t :: l)) "" true | |
| else exp (i - 1) ((Char.escaped s.[i]) :: t :: "*" :: l) "" true | |
| else if getType (Char.escaped s.[i]) = "parenthese" then | |
| if (Char.escaped s.[i]) = ")" then | |
| if c = true then | |
| if t = "" then exp (i - 1) ((Char.escaped s.[i]) :: l) "" true | |
| else exp (i - 1) ((Char.escaped s.[i]) :: "*" :: t :: l) "" true | |
| else if t = "" then exp (i - 1) ((Char.escaped s.[i]) :: "*" :: l) "" true | |
| else exp (i - 1) ( (Char.escaped s.[i]) :: "*" :: t :: "*" :: l ) "" true | |
| else if List.hd l = "(" || List.hd l = ")" then exp (i - 1) ((Char.escaped s.[i]) :: l) "" false (* for "(("或"))"的狀況 *) | |
| else if t != "" then | |
| if c = true then exp (i - 1) ( (Char.escaped s.[i]) :: t :: l ) "" false | |
| else exp (i - 1) ( (Char.escaped s.[i]) :: t :: "*" :: l ) "" false | |
| else exp (i - 1) ((Char.escaped s.[i]) :: l) "" false | |
| else if getType (Char.escaped s.[i]) = "variable" then | |
| if c = true then | |
| if t = "" then exp (i - 1) ((Char.escaped s.[i]) :: l) "" false | |
| else exp (i - 1) ((Char.escaped s.[i]) :: "*" :: t :: l) "" false | |
| else if t = "" then exp (i - 1) ((Char.escaped s.[i]) :: "*" :: l) "" false | |
| else exp (i - 1) ( (Char.escaped s.[i]) :: "*" :: t :: "*" :: l ) "" false | |
| else if getType (Char.escaped s.[i]) = "power" then | |
| if c = true then | |
| if t = "" then exp (i - 2) ( ( (Char.escaped s.[i-1])^(Char.escaped s.[i])^(Char.escaped s.[i+1]) ) :: (List.rev (List.tl (List.rev l))) ) "" false | |
| else exp (i - 2) ( ( (Char.escaped s.[i-1])^(Char.escaped s.[i])^t ) :: l ) "" false | |
| else if t = "" then exp (i - 2) ( ( (Char.escaped s.[i-1])^(Char.escaped s.[i])^(Char.escaped s.[i+1]) ) :: (List.rev (List.tl (List.rev l))) ) "" false | |
| else exp (i - 2) ( ( (Char.escaped s.[i-1])^(Char.escaped s.[i])^t ):: "*" :: l ) "" false | |
| else exp (i - 1) l ((Char.escaped s.[i])^t) c in | |
| exp (String.length s - 1) [] "" true | |
| (* 遇到+、-時考慮有沒有被壓在下面且沒有用括號隔開的*、/,有則移到result的stack *) | |
| let rec s1ToPlusOrMinus s = | |
| if s = [] then [] | |
| else match (List.hd s) with | |
| "+" -> s | |
| | "-" -> s | |
| | ")" -> s | |
| | _ -> s1ToPlusOrMinus (List.tl s) | |
| let resultToPlusOrMinus inputS1 inputResult = | |
| let rec resultToPlusOrMinusDetail (s:string list) (result:string list) = | |
| if s = [] then result | |
| else match (List.hd s) with | |
| "+" -> result | |
| | "-" -> result | |
| | ")" -> result | |
| | _ -> resultToPlusOrMinusDetail (List.tl s) ((List.hd s)::result) in | |
| (resultToPlusOrMinusDetail inputS1 [])@inputResult | |
| (* ******************************************************************* *) | |
| (* 遇到右括號直接放入stack,但遇到左括號的時候,要將operator stack(s1)中,在右括號之前的東西都pop出來 *) | |
| let rec s1ToLeftParenthesis s = | |
| if s = [] then [] | |
| else match (List.hd s) with | |
| ")" -> List.tl s | |
| | _ -> s1ToLeftParenthesis (List.tl s) | |
| let resultToLeftParenthesis inputS1 inputResult = | |
| let rec resultToLeftParenthesisDetail (s:string list) (result:string list) = | |
| if s = [] then result | |
| else match (List.hd s) with | |
| ")" -> result | |
| | _ -> resultToLeftParenthesisDetail (List.tl s) ((List.hd s)::result) in | |
| (resultToLeftParenthesisDetail inputS1 [])@inputResult | |
| (* **************************************************************************************** *) | |
| (* 主要function,revstr為使用者輸入的字串轉為string list後reverse後的結果;s1為operator(暫存);result為最後要輸出的結果 *) | |
| (* stack遇到*/)時直接放入s1,遇到+-時要考慮是不是有在s1中的*/被壓在下面,遇到(時要將)之前的operator pop出來 *) | |
| let rec infixToPrefixDetail (revstr:string list) (s1:string list) (result:string list) = | |
| match revstr with | |
| [] -> (List.rev s1)@result | |
| | x::y -> if x = "*" || x = "/" || x = ")" then infixToPrefixDetail y (x::s1) result | |
| else if x = "+" || x = "-" then infixToPrefixDetail y (x::(s1ToPlusOrMinus s1)) (resultToPlusOrMinus s1 result) | |
| else if x = "(" then infixToPrefixDetail y (s1ToLeftParenthesis s1) (resultToLeftParenthesis s1 result) | |
| else infixToPrefixDetail y s1 (x::result) | |
| (* 以 infixToPrefix "a*(b+c*(d+e))+f" 這樣的方式,可以將infix轉為prefix *) | |
| let infixToPrefix input = infixToPrefixDetail (List.rev (explode input)) [] [] | |
| (* ****************************************** *) | |
| (* hw8 start *) | |
| (* let tempVariableIndex = [|"constant";"x";"y"|] *) | |
| (* let tempVariableIndex = Array.of_list (List.rev tempList) *) | |
| let variableIndex variable variableArray = | |
| let rec variableIndexDetail variable index variableArray = | |
| if index >= (Array.length variableArray) then -1 | |
| else if variable = variableArray.(index) then index | |
| else variableIndexDetail variable (index+1) variableArray in | |
| variableIndexDetail variable 0 variableArray | |
| exception Oops2 | |
| (* convert a variable (x, x^2, etc.) into array ( [|1,1,0|], [|1,2,0|], etc. *) | |
| let convertToLeaf input variableArray = | |
| let tempArray = Array.make (Array.length variableArray) 0 in | |
| (* let convertToLeafDetail input tempArray finished = *) | |
| (* if finished then tempArray *) | |
| if String.contains input '^' then | |
| let indexOfVariable = variableIndex (String.sub input 0 (String.index input '^')) variableArray in | |
| if indexOfVariable != -1 && (Array.set tempArray 0 1) = () && (Array.set tempArray indexOfVariable (int_of_string (String.sub input ((String.index input '^')+1) ((String.length input)-(String.index input '^')-1)))) = () then tempArray | |
| else raise Oops | |
| else if getType input = "variable" && (Array.set tempArray 0 1) = () && (Array.set tempArray (variableIndex input variableArray) 1) = () then tempArray | |
| else if (Array.set tempArray 0 (int_of_string input)) = () then tempArray | |
| else raise Oops | |
| (* convertToLeafDetail input (Array.make (Array.length tempVariableIndex) 0) false *) | |
| (* let addTreeValue aTree a = match a with *) | |
| let rec isLeft aTree = match aTree with | |
| Empty -> true | |
| | Leaf (w) -> false | |
| | Node (x, y ,z) -> isLeft y || isRight y | |
| and isRight aTree = match aTree with | |
| Empty -> true | |
| | Leaf (w) -> false | |
| | Node (x, y ,z) -> isLeft z || isRight z | |
| let rec insertOperator aTree x = match aTree with | |
| Empty -> Node(x, Empty, Empty) | |
| | Node(a, l, r) -> if isLeft aTree then Node(a, (insertOperator l x), r) | |
| else if isRight aTree then Node(a, l, (insertOperator r x)) | |
| else raise Oops | |
| | Leaf(a) -> raise Oops | |
| let rec insertNumber aTree x variableArray = match aTree with | |
| Empty -> Leaf( convertToLeaf x variableArray ) | |
| | Node(a, l, r) -> if isLeft aTree then Node(a, (insertNumber l x variableArray), r) | |
| else if isRight aTree then Node(a, l, (insertNumber r x variableArray)) | |
| else raise Oops | |
| | Leaf(a) -> raise Oops | |
| (* 製造variable list *) | |
| (* 確認這個variable是否已應在variable list裡面了 *) | |
| let rec meetVariableBefore input templist = | |
| match templist with | |
| [] -> false | |
| | a::y -> if a = input then true | |
| else meetVariableBefore input y | |
| (* 確認該variable是否已在variable list中,如果不在則加到variable list並回傳list,若已在其中則直接回傳原本的list *) | |
| let addVariableToList input tempList= | |
| if meetVariableBefore input tempList = false then input::tempList | |
| else tempList | |
| (* 將inputList(在此為使用者輸入後經explode過的東西)中為variable的部份做檢視,若未出現過則加入variable list中,最後回傳新增過後的list *) | |
| let rec makeVariableList inputList tempList = | |
| match inputList with | |
| [] -> tempList | |
| | a::y -> if getType a = "variable" then if String.contains a '^' then makeVariableList y (addVariableToList (String.sub a 0 (String.index a '^')) tempList) | |
| else makeVariableList y (addVariableToList a tempList) | |
| else makeVariableList y tempList | |
| (* 將inputList(在此為使用者輸入後經explode過的東西)中為variable的部份做檢視,若未出現過則加入variable list中,最後回傳新增過後的variable Array *) | |
| let makeVariableArray inputList tempList = (Array.of_list (List.rev (makeVariableList inputList tempList))) | |
| let rec formAbstractTreeDetail aList ansTree variableArray = match aList with | |
| [] -> ansTree | |
| | x::y -> if getType x = "number" || getType x = "variable" then formAbstractTreeDetail y (insertNumber ansTree x variableArray) variableArray | |
| else if getType x = "operator" then formAbstractTreeDetail y (insertOperator ansTree x) variableArray | |
| else raise Oops | |
| let formAbstractTree input = formAbstractTreeDetail (infixToPrefix input) Empty (makeVariableArray (explode input) ["y";"x";"Constant"]) | |
| (**) | |
| (*Mike's code*) | |
| let newCompare2 i l1 l2 = | |
| if l1.(i) < l2.(i) then 1 | |
| else if l1.(i) > l2.(i) then -1 | |
| else 0 | |
| let newCompare l1 l2 = | |
| if l1.(1) < l2.(1) then 1 | |
| else if l1.(1) > l2.(1) then -1 | |
| else 0 | |
| let rec doSort aList i = | |
| if i = 0 then aList | |
| else doSort (List.sort (newCompare2 i) aList ) (i-1) | |
| let isZeroLeaf l = | |
| match l with | |
| | Leaf (a) -> if a.(0) = 0 then true | |
| else false | |
| | _ -> false | |
| let plusSimpling aTree = | |
| match aTree with | |
| | Node (o, l,r )-> if (isZeroLeaf l) then r | |
| else if (isZeroLeaf r) then l | |
| else Node (o, l, r) | |
| | _ -> raise Oops | |
| let rec plusSimple aTree = | |
| match aTree with | |
| Empty -> raise Oops | |
| | Node(o, l,r ) -> if o = "+" then plusSimpling (Node (o,(plusSimple l),(plusSimple r)) ) | |
| else Node (o,(plusSimple l),(plusSimple r)) | |
| | Leaf(a) -> Leaf(a) | |
| let multiSimpling aTree = | |
| match aTree with | |
| | Node (o, l,r )-> if (isZeroLeaf l) then l | |
| else if (isZeroLeaf r) then r | |
| else Node (o, l, r) | |
| | _ -> raise Oops | |
| let rec multiSimple aTree = | |
| match aTree with | |
| Empty -> raise Oops | |
| | Node(o, l,r ) -> if o = "*" then multiSimpling (Node (o,(multiSimple l),(multiSimple r)) ) | |
| else Node (o,(multiSimple l),(multiSimple r)) | |
| | Leaf(a) -> Leaf(a) | |
| (*減法中出現零的話 會將他簡單化 *) | |
| (*使用方式就是 (fun) minusSimple aTree(你想要簡化的樹) *) | |
| let minusSimpling aTree = | |
| match aTree with | |
| | Node (o, l,r )-> if (isZeroLeaf r) then l | |
| else Node (o, l, r) | |
| | _ -> raise Oops | |
| let rec minusSimple aTree = | |
| match aTree with | |
| Empty -> raise Oops | |
| | Node(o, l,r ) -> if o = "-" then minusSimpling (Node (o,(minusSimple l),(minusSimple r)) ) | |
| else Node (o,(minusSimple l),(minusSimple r)) | |
| | Leaf(a) -> Leaf(a) | |
| let rec getLeaf leaf res i= | |
| if i >= Array.length leaf then res | |
| else leaf.(i)::(getLeaf leaf res (i+1)) | |
| let rec equalxy l r i= | |
| if i >= Array.length l then true | |
| else if l.(i) = r.(i) then equalxy l r (i+1) | |
| else false | |
| let rec equalList l r = | |
| match r with | |
| [] -> false | |
| | a::y -> if (equalxy l a 1) then true | |
| else equalList l y | |
| let returnSetArray a i e = | |
| Array.set a i e; | |
| (a) | |
| (*加法函式庫*) | |
| let rec plused res target return i = | |
| if i >= Array.length res then return | |
| else if i = 0 then plused res target (returnSetArray return i (res.(i)+target.(i)) ) (i+1) | |
| else plused res target (returnSetArray return i (res.(i))) (i+1) | |
| let rec plusing2 l r i = | |
| match r with | |
| [] -> raise Oops | |
| | a::y -> if (equalxy l a 1) then (plused l a (Array.create (Array.length l) 0 ) 0 )::y | |
| else a::(plusing2 l y i) | |
| let plusing l r i= | |
| if ( equalList l r ) then (plusing2 l r i) | |
| else l::r | |
| let rec plus l r i = | |
| if l = [] then r | |
| else (plus (List.tl l) (plusing (List.hd l) r i ) i ) | |
| (*加法函式庫 結束*) | |
| (*減法函式庫*) | |
| let rec minused res target return i = | |
| if i >= Array.length res then return | |
| else if i = 0 then minused res target (returnSetArray return i (res.(i)-target.(i)) ) (i+1) | |
| else minused res target (returnSetArray return i (res.(i))) (i+1) | |
| let rec minusing2 l r i = | |
| match l with | |
| [] -> raise Oops | |
| | a::y -> if (equalxy a r 1) then (minused a r (Array.create (Array.length a) 0 ) 0 )::y | |
| else a::(minusing2 y r i) | |
| let minusing l r i= | |
| if ( equalList r l ) then (minusing2 l r i) | |
| else l@( (returnSetArray r 0 (r.(0)*i) )::[] ) | |
| let rec minus l r i = | |
| if r = [] then l | |
| else (minus ( minusing l (List.hd r) i ) (List.tl r) i ) | |
| (*減法函式庫 結束*) | |
| (*乘法函式庫*) | |
| let rec domulti res target return i = | |
| if i >= Array.length res then return | |
| else if i = 0 then domulti res target (returnSetArray return i (res.(i)*target.(i)) ) (i+1) | |
| else domulti res target (returnSetArray return i (res.(i)+target.(i))) (i+1) | |
| let rec multiing l r = | |
| if r <> [] then (domulti l (List.hd r) (Array.create (Array.length l) 0 ) 0 )::(multiing l (List.tl r)) | |
| else [] | |
| let rec multi l r res = | |
| if l = [] then res | |
| else (multi (List.tl l ) r (plus (multiing (List.hd l) r ) res 1) ) | |
| let rec doSimple aTree = | |
| match aTree with | |
| Empty -> raise Oops | |
| | Leaf (a) -> a::[] | |
| | Node(o, l,r ) -> if o = "+" then (plus (doSimple l) (doSimple r) 1) | |
| else if o = "-" then (minus (doSimple l) (doSimple r) (-1)) | |
| else if o = "*" then (multi (doSimple l) (doSimple r) []) | |
| (*else if o = "/" then (divi (doSimple l) (doSimple r) [])*) | |
| else raise Oops | |
| | _ -> raise WrongType | |
| let rec anyVariable a i = | |
| if i >= Array.length a then false | |
| else if a.(i) > 0 then true | |
| else anyVariable a (i+1) | |
| let rec newString aList aArray i result = | |
| if i >= Array.length aArray then result | |
| else if aList.(i) = 0 then newString aList aArray (i+1) result | |
| else if i = 0 then if (aList.(i)=1) && (anyVariable aList 1) then newString aList aArray (i+1) result | |
| else newString aList aArray (i+1) (result^(string_of_int aList.(i)) ) | |
| else if aList.(i) = 1 then newString aList aArray (i+1) (result^aArray.(i) ) | |
| else newString aList aArray (i+1) (result^aArray.(i)^"^"^(string_of_int aList.(i)) ) | |
| let rec output aList aArray i result = | |
| match aList with | |
| [] -> result | |
| | a::y -> if i > 0 && a.(0) > 0 then "+"::(newString a aArray 0 "")::(output y aArray (i+1) result) | |
| else (newString a aArray 0 "")::(output y aArray (i+1) result) | |
| let simplize aTree = | |
| let s = (doSimple ( minusSimple ( plusSimple aTree ) ) ) in | |
| doSort s ((Array.length (List.hd s))-1) | |
| let startSimplize input = | |
| String.concat "" (output (simplize (formAbstractTree input) ) (makeVariableArray (explode input) ["y";"x";"Constant"]) 0 [] ) | |
| (**) |