动态评估用户添加的 If 语句

Evaluate dynamically user-added If-Statements

提问人:Clms 提问时间:1/2/2016 最后编辑:luk2302Clms 更新时间:1/2/2016 访问量:292

问:

如何实现用户可以添加乘法自定义 if 语句?

例如,假设有一个名为 x 的给定变量,其给定值为 8。 用户看到 x = 8,并有一个用于添加 if 语句的按钮。他单击该按钮,可以插入触发事件的条件(假设它打印“Hello World”)。因此,他在字段中输入“x < 100”,这是真的。因此,打印了“Hello World”。 再次单击按钮后,他可以添加其他条件,例如“x < 7”,这也是正确的。由于这两个条件都为真,因此仍打印“Hello World”。 我想你明白了我问题的重点,尽管我缺乏词汇量。 那么,我如何设法让用户添加在打印“Hello World”之前检查的未定义数量的条件? 我知道的唯一解决方案是限制可能的条件数量,并检查每个条件是否为空/条件说什么。

多谢!

JavaScript 斯威夫特

评论

3赞 Martin R 1/2/2016
你的问题是关于 Swift 还是关于 JavaScript?
2赞 skagedal 1/2/2016
在某个地方,x 不再是 8?:)
0赞 Clms 1/2/2016
不好意思。。忘了提;更多的是关于这个问题背后的逻辑。

答:

1赞 R Menke 1/2/2016 #1

首先,您需要一种在运算符之间切换的方法。一个非常简单的是完美的。只需添加您要使用的所有运算符即可。enum

enum Operator : String {

    case biggerThan = ">"
    case smallerThan = "<"
    case equal = "=="

    init?(string:String) {
        switch string {
        case ">" :
            self = .biggerThan
        case "<" :
            self = .smallerThan
        case "==" :
            self = .equal
        default :
            return nil
        }
    }
}

每次用户单击按钮并插入条件时,都会创建相应的值。Condition

struct Condition {
    var value: Int
    var operation: Operator
}

此函数返回一个 取决于 、 和 选择的 。BoolxinputValueoperator

func checkCondition(x: Int, condition: Condition) -> Bool {
    switch condition.operation {
    case .biggerThan :
        return condition.value > x
    case .smallerThan :
        return condition.value < x
    case .equal :
        return condition.value == x
    }
}

这做同样的事情,但适用于一大堆条件。在这里,您可以实现更多逻辑。例如,如果 all 都需要为 true,则添加 : 。if !result { return false }

func checkAllConditions(x:Int, conditions: [Condition]) {
    for condition in conditions {
        let result = checkCondition(x, condition: condition)
        print(result)
    }
}

现在,您需要做的就是在用户创建条件时将条件存储在数组中

func userCondition(operation:String, input:String) -> Condition? {

    guard let op = Operator(string: operation) else {
        return nil
    }
    guard let doubleValue = Double(input) else {
        return nil
    }

    return Condition(value: Int(doubleValue), operation: op)
}

let conditionA = userCondition("<", input: "10")! // use if let instead of !
let conditionB = userCondition(">", input: "10")! // use if let instead of !
let conditionC = userCondition("==", input: "23")! // use if let instead of !

var x : Int = 23

checkAllConditions(x, conditions: [conditionA,conditionB,conditionC])
1赞 dfrib 1/2/2016 #2
struct MyConditions {
    let myEps: Double = 0.001
    var x: Double
    var lessThan = [Double]()
    var equalTo = [Double]()
    var greaterThan = [Double]()

    init(x: Double) {
        self.x = x
    }

    mutating func addConstraint(operand: Double, op: String) {
        if op == "<" {
            lessThan.append(operand)
        }
        else if op == "==" {
            equalTo.append(operand)
        }
        else if op == ">" {
            greaterThan.append(operand)
        }
    }

    func checkConstraints() -> Bool {
        for op in lessThan {
            if !(x < op) {
                return false
            }
        }
        for op in equalTo {
            if !(x - myEps < op && x + myEps > op) {
                return false
            }
        }
        for op in greaterThan {
            if !(x > op) {
                return false
            }
        }
        return true
    }
}

测试:

func feasibleHelloWorld(x: MyConditions) {
    if x.checkConstraints() {
        print("Hello world!")
    }
}

var x = MyConditions(x: 8)
x.addConstraint(100, op: "<")
x.checkConstraints() // true
feasibleHelloWorld(x) // Hello world!

x.addConstraint(8, op: "==")
x.checkConstraints() // true
feasibleHelloWorld(x) // Hello world!

x.addConstraint(7, op: "<")
x.checkConstraints() // false
feasibleHelloWorld(x) // ... nothing
4赞 luk2302 1/2/2016 #3

除非你想构建一门完整的语言,否则你必须清楚你将在这里允许哪些确切的操作。

例如,和 和 的运算,基本上所有的比较运算( 和 以及)都可以通过以下方式实现:<>==<=>=

/* your X variable, might be var if you desire to change */
let x = 12

/* the array of conditions the user entered */
var conditions : [(((Int, Int) -> Bool), Int)] = []

/* some user input - read as e.g. "x > 2"*/
conditions.append((<, 100))
conditions.append((>, 2))
conditions.append((==, 12))

/* you evaluate all conditions in the following way */
let eval = conditions.map { $0(x, $1) }
let allTrue = !eval.contains(false)
/* allTrue would be true in this case because 12 < 100 && 12 > 2 && 12 == 12 */

你的“困难”工作是现在将用户输入解释为一些.但这并不难,您只需要将文本输入映射到实际运算符即可。condition"<"<

您可以调整上面的代码来照顾,而不是在您需要时轻松摔倒。但是你必须意识到浮点的不准确性和检查相等性时出现的问题(感谢@dfri指出了这一点)。DoubleInt

更困难的部分是关于将条件与上述代码的功能以及您当前在问题中描述的内容相结合。orand

仅仅因为我喜欢闭包:以下是整个输入读取和解析:

func getOperator(str: String) -> ((Int, Int) -> Bool)? {
    switch str {
    case "<":
        return (<)
    case ">":
        return (>)
    case "==":
        return (==)
    case "<=":
        return (<=)
    case ">=":
        return (>=)
    default:
        return nil
    }
}

func parseUserInput(str:String) -> (((Int, Int) -> Bool), Int) {
    var input = str as NSString
    input = input.stringByReplacingOccurrencesOfString(" ", withString: "")
    //let variable = input.substringToIndex(1) // in case you want more than one variable, but that will have to change the entire setup a bit
    // this has to be this "ugly" to incorporate both 1 char and 2 char long operators
    let operato = input.substringFromIndex(1).stringByTrimmingCharactersInSet(NSCharacterSet.alphanumericCharacterSet())
    let number = input.substringFromIndex(operato.lengthOfBytesUsingEncoding(NSASCIIStringEncoding) + 1)

    if let number = Int(number), op = getOperator(operato) {
        return (op, number)
    }

    return ((<, 999999)) // need some error handling here
}

conditions.append(parseUserInput("x > 123"))

您甚至可以使用普通的旧字典映射 from to 等,而不是使用函数解析运算符。">"(>)

评论

1赞 dfrib 1/2/2016
关闭,这很整洁!
2赞 luk2302 1/2/2016
@dfri I <3 个闭合:)
1赞 dfrib 1/2/2016
一些宽容怎么样?不应该搞砸或,但允许在检查时容忍。let eval = conditions.map { ($0(x, $1) || $0(x-MY_TOL, $1) || $0(x+MY_TOL, $1)) } MY_TOL<>==
1赞 luk2302 1/2/2016
@dfri嗯,这看起来不再那么漂亮了。在移动到浮点时,我肯定会包含“警告”语句,但尚未包含任何特殊处理。
2赞 dfrib 1/2/2016
@user1658080 幸运的是,你有三个答案(简单,不那么简洁)-->(有点复杂,非常优雅)。如果你有时间,我认为涵盖所有三个答案可能是一个有价值的练习,因为它们都使用不同的方法来解决同一个问题。从我的基本命令式答案开始,然后继续进行 R Menke 的更简洁的解决方案,最后,尝试掌握上面的 luk2302 非常优雅的解决方案。希望通过逐步更高级的解决方案来解决同一问题,会更容易掌握正在发生的事情。structenum