2016-12-30 1 views
1

入力がさまざまなフォーマットを持つことができるStringパーサで作業していますが、どのフォーマットが使用されているかわからないので、柔軟なものを書く必要があります。異なるフォーマットのスウィートパースストリング

最初のステップは、私が例えばを使用していることを確認することができ、最初の数文字をチェックすることです:

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()機能は、それが再び、このような異なるなど、複数のオプションを持つことができる独自の解析コード、のしています区切り文字などを使用することができます。

これは、if-elseコードに簡単に変わる可能性があります。これを行うには、Swiftには簡単な方法があるのでしょうか。たぶんswitch-caseステートメントなどを使用していますか?これにenumを使用できますか?

EDIT:コードはString内にあります。ここで

答えて

2

は、私はそれを行うだろう方法は次のとおりです。

// 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) 
} 
+0

有望に見えること。残念ながら、最初の 'func'のコンパイラエラーが発生しました:' Member operator '〜=' 'String';型の引数が少なくとも1つ必要です; '' func'に 'static'キーワードを追加する必要がありました。私は、 'String'拡張子に解析コードを持っています。そのエラーを引き起こす可能性がありますか? – Koen

+1

私は意図的に '〜= '演算子を汎用にしました。だから、どの型にも当てはまります。この場合、フリースタンディング機能でなければなりません。もしあなたが本当に 'String'拡張でそれを保持したいのであれば、それを一般的な' T'ではなく 'String'をとるように特殊化することができますが、これに対しては助言します。 – Alexander

+0

私はそれを変更し、今は(私は 'parse2'を使用しています)動作します。 – Koen

関連する問題