评估

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

PostfixEvaluation 类

这个类让你能够从后缀标记中进行评估。

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 类

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 扩展

我们添加了 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 会抛出带有属性 kinddescriptionEvaluationError 结构体

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 Manager

你可以将此添加到 Package.swift

dependencies: [
	.package(url: "https://github.com/Swift-Squirrel/Evaluation.git", from: "0.3.1")
]