swift casting integer range nsrange

range swift



Trate un solo valor entero como un rango en Swift (2)

Necesito validar la longitud de una cadena. Los valores permitidos para el recuento de caracteres son:

  • 6 - 9 caracteres
  • 12 caracteres
  • 15 caracteres

Todas las cadenas con un recuento de caracteres diferente no son válidas. Por lo tanto, me gustaría crear una función Swift que acepte varios rangos y evalúe la cadena:

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

Ahora puedo llamar a la función para un único rango Int :

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

y múltiples rangos Int :

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

Pero no puedo llamar a la función con valores enteros únicos y aislados:

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

porque 12 y 15 se escriben como Int y no como Range<Int> .

Error de compilación Swift: no se puede convertir el valor del tipo ''Int'' al tipo de argumento esperado ''Rango''

¿Hay alguna forma de tratar un Entero único como un Range en Swift, como lanzarlo automáticamente a Range<Int> ?

(Después de que 5 es equivalente a 5..<6 , matemáticamente hablando, 5 es un rango).


Así es como lo haría. En lugar de ocuparme de la semántica del rango, solo estoy creando una extensión Establecer con un inicializador relevante.

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

Esto le permite pasar solo valores únicos, solo rangos o ambos. La única advertencia es los params nombrados que los separan.

La semántica Set también significa que puede crear constantes estáticas si así lo desea y también debe ser significativamente más rápido.


Se me ocurrieron 3 soluciones pero ninguna de ellas es tan agradable como sería si el método acepta Int o Range<Int> pero aquí vamos?

1 - Tiene seguridad tipo pero tiene que usar algunas soluciones:

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 - No tiene seguridad de tipo:

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 - La mejor solución hasta ahora, pero aún no perfecta:

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