index - Swift에서 단일 정수 값을 범위로 취급




swift string substring nsrange (2)

문자열의 길이를 확인해야합니다. 문자 수에 허용되는 값은 다음과 같습니다.

  • 6 - 9 자
  • 12 자
  • 15 자

문자 수가 다른 모든 문자열은 유효하지 않습니다. 따라서 여러 범위를 받아들이고 문자열을 평가하는 Swift 함수를 만들고 싶습니다.

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)

1215Range<Int> 아닌 Int 로 입력되기 때문입니다.

빠른 컴파일 오류 : 'Int'유형의 값을 예상 인수 유형 'Range'로 변환 할 수 없습니다 .

Range<Int> 자동으로 캐스팅하는 것처럼 하나의 Integer를 Swift에서 Range 로 처리하는 방법이 있습니까?

(모두 55..<6 과 같기 때문에 수학적으로 말하면 5 도 범위입니다.)


3 가지 솔루션을 생각해 냈습니다. 그러나 그 중 하나가 Int 또는 Range<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

이것이 내가하는 방법이다. 범위 의미를 다루는 대신 관련 이니셜 라이저를 사용하여 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 semantics는 원하는 경우 정적 상수를 생성 할 수 있다는 것을 의미하며 훨씬 더 빨라야합니다.





nsrange