Evaluation 是一个 Swift 库,可以评估 String 的内容并返回结果或后缀表示法。 这个库也可以在 Linux 上运行 :)
操作数必须是相同类型
操作 | 优先级 | 类型 | 操作数类型 |
---|---|---|---|
! |
200 | 一元 | Bool |
* |
150 | 二元 | Int , UInt , Double , Float |
/ |
150 | 二元 | Int , UInt , Double , Float |
% |
150 | 二元 | Int , UInt |
+ |
140 | 二元 | Int , UInt , Double , Float , String |
- |
140 | 二元 | Int , UInt , Double , Float |
?? |
131 | 二元 | Any? |
== |
130 | 二元 | Int , UInt , Double , Float , String , Bool , nil |
!= |
130 | 二元 | Int , UInt , Double , Float , String , Bool , nil |
< |
130 | 二元 | Int , UInt , Double , Float , String |
<= |
130 | 二元 | Int , UInt , Double , Float , String |
> |
130 | 二元 | Int , UInt , Double , Float , String |
>= |
130 | 二元 | Int , UInt , Double , Float , String |
&& |
120 | 二元 | Bool |
|| |
110 | 二元 | Bool |
你可以使用这些函数进行类型转换
String(_) -> String
Double(_) -> Double?
Float(_) -> Float?
Int(_) -> Int?
UInt(_) -> UInt?
Bool(_) -> Bool?
你可以使用 String 扩展或 Evaluation
类来进行评估,只需记住导入库
import Evaluation
这个类让你能够从后缀标记中进行评估。
public class PostfixEvaluation {
/// Serialized postfix in JSON format
public func serializedPostfix() throws -> Data
public func serializedPostfix() throws -> String
public var postfix: [PostfixEvaluation.Token] { get }
/// Construct from JSON
public init(postfix: [PostfixEvaluation.Token])
public init(postfix: String) throws
public init(postfixData: Data) throws
/// Evaluate
public func evaluate(with data: [String: Any] = [:]) throws -> Any?
}
InfixEvaluation 类将过程分为两个部分,第一部分是标记解析和后缀转换,第二部分是评估表达式。
public class InfixEvaluation: PostfixEvaluation {
/// Serialized postfix in JSON format
public func serializedPostfix() throws -> Data
public func serializedPostfix() throws -> String
/// Perform lexical analysis and makes postfix notation of given expression
///
/// - Parameter string: expression
/// - Throws: lexical and syntax error as `EvaluationError`
public init(expression string: String) throws
/// Evaluate expression and return result
///
/// - Parameter data: Dictionary with variables used in expression
/// - Returns: result of expression
/// - Throws: EvaluationError
public func evaluate(with data: [String : Any] = default) throws -> Any?
}
我们添加了 String 扩展,所以你只需要编写
try "1+5".evaluate() as! Int // 6
"1+5".evaluateAsInt()! // 6
public extension String {
public func evaluate(with data: [String : Any] = default) throws -> Any?
public func evaluateAsString(with data: [String : Any] = default) -> String?
public func evaluateAsBool(with data: [String : Any] = default) -> Bool?
public func evaluateAsInt(with data: [String : Any] = default) -> Int?
public func evaluateAsUInt(with data: [String : Any] = default) -> UInt?
public func evaluateAsDouble(with data: [String : Any] = default) -> Double?
public func evaluateAsFloat(with data: [String : Any] = default) -> Float?
}
你可以在评估中使用变量,如果你传递 [String: Any]
给 evaluate(with:)
,那么你可以使用点表示法访问它们
let data: [String: Any] = [
"name": "John",
"sleeps": 8
]
// John is awake 16 hours per day
"name + \" is awake \" + String(24 - sleeps) + \" hours per day\"".evaluateAsString(with: data)!
如果你确定变量类型([Any] 或 [String: Any]),你可以使用 .count
来获取元素的数量
let data: [String: Any] = [
"numbers": [1, 2 ,3 , 4]
]
"numbers.count".evaluateAsInt(with: data)! // 4
import Evaluation
// If you wan to know if something goes wrong use Evaluation class
do {
let eval = try InfixEvaluation(expression: "1 + 5 < seven")
if let result = (try eval.evaluate(with: ["seven": 7])) as? Bool {
print(result) // true
}
} catch let error {
print(error)
}
// when you are interested only in result you can use extension
print("1 + 5".evaluateAsInt()!) // 6
let data = [
"person1": [
"name": "Matt",
"age": 21,
"male": true,
"children": [
"Ann",
"Matt Jr."
]
],
"person2": [
"name": "Miriam",
"age": 19,
"male": false,
"children": [String]()
]
]
print("person1.name != person2.name".evaluateAsBool(with: data)!) // true
print("person1.children.count == person2.children.count".evaluateAsBool(with: data)!) // false
// You can change type like this
print("Int( (Double(person1.age) + Double(person2.age)) / 2.0 )".evaluateAsInt(with: data)!) // 20
// JSON usage
do {
let infixEval = try InfixEvaluation(expression: "3 + 1")
let postfix: String = try infixEval.serializedPostfix()
print(postfix) // [{"type":{"int":"Int"},"value":"3"},{"type":{"int":"Int"},"value":"1"},{"type":{"operation":"+"},"value":"+"}]
let postfixEval = try PostfixEvaluation(postfix: postfix)
let result = try postfixEval.evaluate() as! Int
print(result) // 4
} catch let error {
print(error)
}
如果出现问题,Evaluation 会抛出带有属性 kind
和 description
的 EvaluationError
结构体
public struct EvaluationError: Error, CustomStringConvertible {
public enum ErrorKind {
case canNotApplyBinOperand(oper: String, type1: String, type2: String)
case canNotApplyUnaryOperand(oper: String, type: String)
case unexpectedEnd(reading: String)
case unexpectedCharacter(reading: String, expected: String, got: String)
case syntaxError
case missingValue(forOperand: String)
case nilFound(expr: String)
case decodingError
case encodingError
case unknownOperation(operation: String)
}
/// Error kind
public let kind: ErrorKind
/// A textual representation of this instance.
public var description: String { get }
}
你可以将此添加到 Package.swift
dependencies: [
.package(url: "https://github.com/Swift-Squirrel/Evaluation.git", from: "0.3.1")
]