Skip to content

Instantly share code, notes, and snippets.

@DianQK
Created June 20, 2016 14:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DianQK/d6ef7573ae5e21e04801b2021b5f9d4c to your computer and use it in GitHub Desktop.
Save DianQK/d6ef7573ae5e21e04801b2021b5f9d4c to your computer and use it in GitHub Desktop.
enum CalculatorError: ErrorType {
case RejectCharacter(Character) // 不接受的字符
case ActionNilXXX // * / 乘除前面没有 可以值
case ActionDuplicate // 符号写一起了,白痴
case ParenthesesDuplicate // 多写了个 )
}
enum CalculatorNode: CustomStringConvertible {
case number(String)
case action(Character)
case calculator(Calculator)
var description: String {
switch self {
case .number(let num):
return "Number: \(num)"
case .action(let char):
return "Action: \(char)"
case .calculator(let cal):
return "Calculator: \(cal.nodes)"
}
}
}
extension CalculatorNode: Hashable, Equatable {
var hashValue: Int {
switch self {
case .number(let num):
return num.hashValue
case .action(let char):
return char.hashValue
case .calculator(let cal):
return "\(cal)".hashValue // ==
}
}
}
func ==(lhs: CalculatorNode, rhs: CalculatorNode) -> Bool {
return lhs.hashValue == rhs.hashValue
}
class Calculator {
private(set) var nodes: [CalculatorNode] = []
private var final = false
func add(character character: Character) throws {
if ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "."].contains(character) {
if let lastNode = nodes.last {
switch lastNode {
case .number(let num):
nodes.removeLast()
let newNode = CalculatorNode.number(num + String(character))
nodes.append(newNode)
case .action:
nodes.append(CalculatorNode.number(String(character)))
case .calculator(let cal) where cal.final:
nodes.append(CalculatorNode.number(String(character)))
case .calculator(let cal) where !cal.final:
try cal.add(character: character)
default:
fatalError("什么鬼,怎么可能走到这里")
}
} else {
nodes.append(CalculatorNode.number(String(character)))
}
} else if ["+", "-", "*", "/"].contains(character) {
if let lastNode = nodes.last {
switch lastNode {
case .number:
nodes.append(CalculatorNode.action(character))
case .action:
throw CalculatorError.ActionDuplicate
case .calculator(let cal) where cal.final:
nodes.append(CalculatorNode.action(character))
case .calculator(let cal) where !cal.final:
try cal.add(character: character)
default:
fatalError("什么鬼,怎么可能走到这里")
}
} else {
nodes.append(CalculatorNode.action(character))
}
} else if character == "(" {
if let lastNode = nodes.last {
switch lastNode {
case .number, .action:
nodes.append(CalculatorNode.calculator(Calculator()))
case .calculator(let cal):
try cal.add(character: character)
}
} else {
nodes.append(CalculatorNode.calculator(Calculator()))
}
} else if character == ")" {
if let lastNode = nodes.last {
switch lastNode {
case .number, .action where final:
// throw CalculatorError.ParenthesesDuplicate
print("")
case .number, .action where !final:
final = true
case .calculator(let cal) where !cal.final:
try cal.add(character: character)
case .calculator(let cal) where cal.final:
throw CalculatorError.ParenthesesDuplicate
default:
break
}
} else {
final = true
}
} else {
throw CalculatorError.RejectCharacter(character)
}
}
func currentResult() throws -> Float {
var result: Float = 0
// == 先去处理那个括号的优先级
var resultNodes = nodes
while true {
var finished = true
for (index, node) in resultNodes.enumerate() {
switch node {
case .calculator(let cal):
resultNodes.removeAtIndex(index)
resultNodes.insert(CalculatorNode.number(String(try cal.currentResult())), atIndex: index)
finished = false
default:
continue
}
break
}
if finished {
break
}
}
// 处理 */
while true {
var finished = true
for (index, node) in resultNodes.enumerate() {
switch node {
case .action(let char) where ["*", "/"].contains(char):
if index == 0 {
throw CalculatorError.ActionNilXXX
}
let pre = resultNodes[index - 1] // 没有开头的值是应该挂掉的
let next = resultNodes[index + 1]
switch (pre, next) {
case (.number(let preNumber), .number(let nextNumber)):
let result: Float
if char == "*" {
result = Float(preNumber)! * Float(nextNumber)!
finished = false
} else if char == "/" {
result = Float(preNumber)! / Float(nextNumber)!
finished = false
} else {
continue
}
resultNodes.removeAtIndex(index - 1)
resultNodes.removeAtIndex(index - 1)
resultNodes.removeAtIndex(index - 1)
resultNodes.insert(CalculatorNode.number(String(result)), atIndex: index - 1)
break
default:
fatalError()
}
case .number:
continue
case .calculator(let cal):
resultNodes.removeAtIndex(index)
resultNodes.insert(CalculatorNode.number(String(try cal.currentResult())), atIndex: index)
default:
continue
}
break
}
if finished {
break
}
}
// +-
while resultNodes.count > 1 {
for (index, node) in resultNodes.enumerate() {
switch node {
case .action(let char):
let pre = index == 0 ? CalculatorNode.number("0") : resultNodes[index - 1]
let next = resultNodes[index + 1]
switch (pre, next) {
case (.number(let preNumber), .number(let nextNumber)):
let result: Float
if char == "+" {
result = Float(preNumber)! + Float(nextNumber)!
} else if char == "-" {
result = Float(preNumber)! - Float(nextNumber)!
} else {
fatalError()
}
if index == 0 {
resultNodes.removeFirst(2)
resultNodes.insert(CalculatorNode.number(String(result)), atIndex: index)
} else {
resultNodes.removeAtIndex(index - 1)
resultNodes.removeAtIndex(index - 1)
resultNodes.removeAtIndex(index - 1)
resultNodes.insert(CalculatorNode.number(String(result)), atIndex: index - 1)
}
default:
fatalError()
}
case .number:
continue
case .calculator(let cal):
resultNodes.removeAtIndex(index)
resultNodes.insert(CalculatorNode.number(String(try cal.currentResult())), atIndex: index)
}
break
}
}
if let node = resultNodes.first {
switch node {
case .number(let num):
result = Float(num)!
case .action, .calculator:
fatalError()
}
}
return result
}
func prase(string: String) throws -> Float {
for char in string.characters {
try add(character: char)
}
return try currentResult()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment