为具有整数范围的字符串创建一个SUBSCRIPT EXTENSION

时间:2019-02-11 13:55:56

标签: swift string range

此具有两个整数的解决方案有效,但我想改用范围:

extension String {
   subscript(start: Int, end: Int) -> String? {
      return String(self[index(startIndex, offsetBy: start#)...index(startIndex, offsetBy: end)])
   }
}

以下两个解决方案使用范围,但都产生相同的错误,不是在扩展代码中,而是在尝试使用它时:

  

'下标'不可用:不能下标整数范围的字符串。

这是一个荒谬的错误,基本上是在告诉我String没有范围下标,而实际上我只是创建了它,因此它确实存在。

extension String {
   subscript(range: Range<String.IndexDistance>) -> String? {
      return String(self[index(startIndex, offsetBy: range.startIndex)...index(startIndex, offsetBy: range.endIndex)])
   }

   subscript(range: Range<Int>) -> String? {
      return String(self[index(startIndex, offsetBy: range.startIndex)...index(startIndex, offsetBy: range.endIndex)])
   }
}

let greeting = "Hello, World"
print(greeting[0...4]) // should print "Hello"

2 个答案:

答案 0 :(得分:1)

编译器错误并非意外。范围0...4的类型不是Range<Int>,而是ClosedRange<Int>,它们是不相关的类型。如果您将subscript实现修改为采用ClosedRange<Int>而不是Range<Int>,则代码将编译并可以正常工作。

extension String {
    subscript(range: ClosedRange<Int>) -> String? {
        return String(self[index(startIndex, offsetBy: range.lowerBound)...index(startIndex, offsetBy: range.upperBound)])
    }
}

如果您想返回nil以防万一任何索引都会产生超出范围的异常,则可以使用index(_:,offsetBy:,limitedBy:)

extension String {
    subscript(range: ClosedRange<Int>) -> String? {
        guard let startIndex = index(startIndex, offsetBy: range.lowerBound,limitedBy: endIndex), let endIndex = index(startIndex, offsetBy: range.upperBound,limitedBy: endIndex) else { return nil }
        return String(self[startIndex...endIndex])
    }
}

答案 1 :(得分:0)

基于@Dávid Pásztor 代码的正确答案:

extension String {
    subscript(range: ClosedRange<Int>) -> String? {
        guard let startIdx = index(startIndex, offsetBy: range.lowerBound,limitedBy: endIndex), let endIdx = index(startIndex, offsetBy: range.upperBound,limitedBy: endIndex) else { return nil }
        return String(self[startIdx...endIdx])
     }   
}

这里是错误发生的地方

let startIndex = index(startIndex, offsetBy: range.lowerBound,limitedBy: endIndex)

// startIndex shall be self. startIndex, name does matter
let endIndex = index(startIndex, offsetBy: range.upperBound,limitedBy: endIndex)