Swift 解析不同格式的字符串 [英] Swift parse string with different formats

查看:58
本文介绍了Swift 解析不同格式的字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个 String 解析器,其中输入可以有多种格式,但我事先不知道使用的是哪种格式,所以我需要编写一些灵活的东西.

I am working on a String parser in which the input can have various formats, and I don't know in advance which format is being used, so I need to write something that is flexible.

第一步是检查前几个字符,我可以使用例如:

The first step is to check the first few characters, I can check that by using eg:

func parse(input: String) -> String {

   let result: String

   if (input.hasPrefix("foo") {
     result = doFoo(input)
   }
   else if (input.hasPrefix("bar") {
     result = doBar(input)
   }
   else if (input.hasPrefix("baz") {
     result = doBaz(input)
   }
   else {
     result = doBasic(input)
   }

   return result
}

并且每个doXXX()函数都有自己的解析代码,同样可以有多个选项,例如不同的分隔符等.

and every doXXX() function has it's own parsing code, which again could have multiple options, such as different delimiters, etc.

这很容易变成很多 if-else 代码,我想知道 Swift 是否有更简单的方法来做到这一点.也许使用 switch-case 语句或其他什么?我可以为此使用枚举吗?

This could easily turn into lots of if-else code, and I am wondering if with Swift there is a simpler way to do this. Maybe using switch-case statements, or something else? Could I use an enum for this?

代码在 String 扩展中.

推荐答案

我会这样做:

// This pattern matching operator defines what it means to have a
// closure as a pattern.  If the closure evaluates to true when called
// with `value` as an arg, then the `pattern` matches the `value`.
func ~=<T>(pattern: (T) -> Bool, value: T) -> Bool {
    return pattern(value)
}

// This type alias is just here to make the next line a bit more readable.
// A `BoolInstanceMethod<T, U>` is a closure type that represents an unapplied
// instance method that ultimately returns a Bool.

// For example, `String.hasPrefix` has type `(String) -> (String) -> Bool`.
// The first argument, of type `T` (String, in this case) is the instance
// this method will be called on.

// Say we call this: String.hasPrefix("The quick brown fox").
// The result has type `(String) -> Bool`.
// It's equivalent to "The quick brown fox".hasPrefix.

// We then call the resulting closure with the arguement to hasPrefix
// For example: String.hasPrefix("The quick brown fox")("The")
// This has type `Bool`. It's the same as: "The quick brown fox".hasPrefix("The)
typealias BoolInstanceMethod<T, U> = (_ instance: T) -> (_ arg: U) -> Bool

// This function wraps a given instance method, in such a way as to reverse the
// order of the curried arguements. The given instance method is usually called as:
// Type.instanceMethod(instance)(arg), but this function allows you to swap it, to
// call it as: apply(Type.instanceMethod)(arg)(instance)
func apply<T, U>(instanceMethod: @escaping BoolInstanceMethod<T, U>) -> (_ arg: U) -> (_ instance: T) -> Bool {
    return { arg in
        return { instance in
            return instanceMethod(instance)(arg)
        }
    }
}

// Dummy functions to satisfy the compiler
func doFoo(_: String) -> String { return "" }
func doBar(_: String) -> String { return "" }
func doBaz(_: String) -> String { return "" }
func doBasic(_: String) -> String { return "" }

func parse(input: String) -> String {
    let result: String

    // The predicate of choice is made, in this case, String.hasPrefix.
    let hasPrefix = apply(instanceMethod: String.hasPrefix)

    // The switch calls `~=` for every case, giving it hasPrefix(...) and "input"
    // as args. The first case that makes `~=` yield `true` is executed.
    switch input {
    case hasPrefix("foo"): result = doFoo(input)
    case hasPrefix("bar"): result = doBar(input)
    case hasPrefix("baz"): result = doBaz(input)
    default: result = doBasic(input)
    }

    return result
}

// You could also implement parse like this:
func parse2(input: String) -> String {
    // You can save repeated application of the `input` parameter by doing it
    // just once at the end (see the `return` of this func).
    let action: (String) -> String

    // The predicate of choice is made, in this case, String.hasPrefix.
    let hasPrefix = apply(instanceMethod: String.hasPrefix)

    // The switch calls `~=` for every case, giving it hasPrefix(...) and "input"
    // as args. The first case that makes `~=` yield `true` is executed.

    switch input {
    case hasPrefix("foo"): action = doFoo
    case hasPrefix("bar"): action = doBar
    case hasPrefix("baz"): action = doBaz
    default: action = doBasic
    }

    return action(input)
}

这篇关于Swift 解析不同格式的字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆