2017-08-10 61 views
2

我需要驗證字符串的長度。爲字符計數的允許值包括:將單個整數值視爲Swift中的一個範圍

  • 6 - 9個字符
  • 12個字符
  • 15個字符

所有字符串與不同的字符計數是無效的。因此,我想創建接受一個數範圍,並評估串的夫特功能:

extension String { 

    func evaluateLength(validCharacterCounts: Range<Int>...) -> Bool { 
     // Implementation 
    } 

} 

現在我可以調用該函數用於單個Int範圍:

"Live long and prosper".evaluateLength(validCharacterCounts: 6..<10) 

和多個Int範圍:

"Live long and prosper".evaluateLength(validCharacterCounts: 6..<10, 15..<20) 

但我不能用單一的,分離的整數值調用函數:

"Live long and prosper".evaluateLength(validCharacterCounts: 6..<10, 12, 15) 

因爲1215被分類爲Int而不是Range<Int>

Swift compile error: Cannot convert value of type 'Int' to expected argument type 'Range'

有沒有一種方式來對待一個整數,如斯威夫特一個Range,像自動澆鑄成Range<Int>

(畢竟5相當於5..<6,所以從數學上講5是一個範圍爲好。)

+0

另一種方法是傳遞一個'IndexSet'類型的參數。 –

+0

你的意思是像'evaluateLength(validCharacterCounts:IndexSet(6 .. <10),IndexSet(12,15))'?或者是否有一個帶有'IndexSet'的整潔的解決方案,它允許類似上述的語法? – Mischa

回答

0

我想出了3個解決方案,但我也不都是那樣令人開心的是,如果該方法接受IntRange<Int>但我們在這裏?

1 - 你有類型安全,而且必須使用一些變通方法:

extension String { 
    func evaluateLength(validCharacterCounts: [Range<Int>]? = nil) -> Bool { 
     if let validCharCounts = validCharacterCounts { 
      for validCharCount in validCharCounts { 
       if validCharCount.contains(characters.count) { 
        return true 
       } 
      } 
     } 

     return false 
    } 
} 

extension Int { 
    var asRange: Range<Int> { 
     return self..<self+1 as Range<Int> 
    } 
} 

"Hello, playground".evaluateLength(validCharacterCounts: [17.asRange, 1, 25, 1..<45]) // true 

2 - 您沒有類型安全:

extension String { 
    func evaluateLength(validCharacterCounts: [Any]? = nil) -> Bool { 
     if let validCharCounts = validCharacterCounts { 
      for validCharCount in validCharCounts { 
       if let range = validCharCount as? Range<Int> { 
        if range.contains(characters.count) { 
         return true 
        } 
       } else if let range = validCharCount as? CountableRange<Int> { 
        if range.contains(characters.count) { 
         return true 
        } 
       } else if let range = validCharCount as? CountableClosedRange<Int> { 
        if range.contains(characters.count) { 
         return true 
        } 
       } else if let int = validCharCount as? Int { 
        if int.asRange.contains(characters.count) { 
         return true 
        } 
       } else { 
        fatalError("Unexpected type: \(type(of: validCharCount))") 
       } 
      } 
     } 

     return false 
    } 
} 

extension Int { 
    var asRange: Range<Int> { 
     return self..<self+1 as Range<Int> 
    } 
} 

"Hello, playground".evaluateLength(validCharacterCounts: [12, 1, 4, 6, 14...18]) // true 

3 - 迄今最好的,但仍不完美的解決方案:

extension String { 
    func evaluateLength(validCharacterCounts: [Int]? = nil) -> Bool { 
     guard let validCharCounts = validCharacterCounts else { 
      return false 
     } 

     return validCharCounts.contains(characters.count) 

    } 
} 

"Hello, playground".evaluateLength(validCharacterCounts: [12, 1, 4, 6] + Array(14...18)) // true 
+0

我很喜歡類型安全,所以我不太欣賞2。 3幾乎是我最終實現自己,但它不能解決問題,因爲你仍然需要以不同的方式處理範圍和單個整數。謝謝你的想法! :) – Mischa

0

這是我該怎麼做。而不是處理範圍語義,我只是用相關的初始化工具創建一個Set擴展。

extension Set where Element == Int { 
    init(with elements: [Int] = [], and ranges: Range<Int>...) { 
     var allElements = [elements] 
     ranges.forEach { 
      allElements.append(Array($0.lowerBound..<$0.upperBound)) 
     } 
     self.init(allElements.joined()) 
    } 
} 

let newSet = Set(with: [1, 3, 328], and: 6..<10, 15..<20) 
newSet.contains(3) //true 
newSet.contains(4) //false 
newSet.contains(16) //true 

這允許您僅傳遞單個值,僅傳遞範圍或兩者。唯一的注意事項是命名的參數將它們分開。

Set語義也意味着你可以創建靜態常量,如果需要,也應該明顯更快。

+0

我一直在嘗試使用Sets。但是,這種方法在兩個不同整數之間引入了「單個整數範圍」和「實際」間隔之間的分隔。這就是爲什麼我問這個問題的原因,因爲它們在語義上是_both_範圍,所以我想以相同的方式對待它們。 – Mischa

+0

'evaluateLength(validCharacterCounts:5,7,10 ... 20,25)'比'evaluateLength(validCharacterCounts:5,7,25,validCharacterCountRanges:10 ... 20)'更直觀。 – Mischa

+0

@Mischa我同意這樣做很好,我試圖找到一種協議的方式,但它可能不是類型安全目前可能的。 (這可能會在Swift 4中改變) – PeejWeej

相關問題