'subscript'不可用:不能使用CountableClosedRange <int>下标String,请参阅文档注释以供讨论

时间:2017-08-04 03:12:14

标签: swift string swift4

在Swift 4中,当我尝试使用下标语法Substring String时,我收到此错误。

  

'subscript'不可用:不能使用CountableClosedRange下标String,请参阅文档注释以供讨论

例如:

let myString: String = "foobar"
let mySubstring: Substring = myString[1..<3]

两个问题:

  1. 如何解决此错误?
  2. 错误中提到的“讨论文档评论”在哪里?

8 个答案:

答案 0 :(得分:56)

  1. 如果您想在"palindrome"[1..<3]"palindrome"[1...3]等字符串上使用下标,请使用这些扩展程序。
  2. Swift 4

    extension String {
        subscript (bounds: CountableClosedRange<Int>) -> String {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return String(self[start...end])
        }
    
        subscript (bounds: CountableRange<Int>) -> String {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return String(self[start..<end])
        }
    }
    

    Swift 3

    对于Swift 3替换为return self[start...end]return self[start..<end]

    1. Apple没有将其构建为Swift语言,因为'character'的定义取决于String的编码方式。字符可以是8到64位,默认值通常是UTF-16。您可以在String.Index
    2. 中指定其他字符串编码 Xcode错误引用的

      This is the documentation

      More on String encodings like UTF-8 and UTF-16

答案 1 :(得分:19)

你的问题(和自我回答)有两个问题:

使用Int订阅字符串从未在Swift的标准库中提供。只要Swift存在,此代码就无效:

let mySubstring: Substring = myString[1..<3]

String.Index(encodedOffset: )以UTF-16(16位)编码返回索引。 Swift的字符串使用 Extended Grapheme Cluster ,它可以使用8到64位来存储一个字符。 Emojis做了非常好的演示:

let myString = ""
let lowerBound = String.Index(encodedOffset: 1)
let upperBound = String.Index(encodedOffset: 3)
let mySubstring = myString[lowerBound..<upperBound]

// Expected: Canadian and UK flags
// Actual  : gibberish
print(mySubstring)

事实上,获得String.Index在Swift 4中根本没有改变,无论好坏:

let myString = ""
let lowerBound = myString.index(myString.startIndex, offsetBy: 1)
let upperBound = myString.index(myString.startIndex, offsetBy: 3)
let mySubstring = myString[lowerBound..<upperBound]

print(mySubstring)

答案 2 :(得分:11)

  
      
  1. 如何解决此错误?
  2.   

此错误意味着您不能在下标格式中使用Int - 您必须使用String.Index,您可以使用encodedOffset Int初始化。

let myString: String = "foobar"
let lowerBound = String.Index.init(encodedOffset: 1)
let upperBound = String.Index.init(encodedOffset: 3)
let mySubstring: Substring = myString[lowerBound..<upperBound]
  
      
  1. 错误中提到的“讨论文档评论”在哪里?
  2.   

它位于Swift标准库存储库中的GitHub中,位于一个名为UnavailableStringAPIs.swift.gyb的文件中,位于一个锁定的文件柜底部,卡在一个废弃的厕所中,门上有一个标语,“小心豹子”。 link

答案 3 :(得分:2)

基于p-sun's answer

快捷键4

extension StringProtocol {
    subscript(bounds: CountableClosedRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(start, offsetBy: bounds.count)
        return self[start..<end]
    }

    subscript(bounds: CountableRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(start, offsetBy: bounds.count)
        return self[start..<end]
    }
}

重要更改:

  • 现在扩展为StringProtocol。这样一来,Substring等采用者也可以获得这些下标。
  • 结束索引从边界的开始索引而不是字符串的开始偏移。这样可以防止从String的开头开始两次遍历。 index方法为O(n),其中n是距i的偏移量。

答案 4 :(得分:1)

建立在p-sun'sJustin Oroz's答案的基础上,这是两个扩展名,用于防止无效索引超出字符串的开头和结尾(这些扩展名也避免了从头开始重新扫描字符串以查找字符串)范围末尾的索引):

extension String {

    subscript(bounds: CountableClosedRange<Int>) -> String {
        let lowerBound = max(0, bounds.lowerBound)
        guard lowerBound < self.count else { return "" }

        let upperBound = min(bounds.upperBound, self.count-1)
        guard upperBound >= 0 else { return "" }

        let i = index(startIndex, offsetBy: lowerBound)
        let j = index(i, offsetBy: upperBound-lowerBound)

        return String(self[i...j])
    }

    subscript(bounds: CountableRange<Int>) -> String {
        let lowerBound = max(0, bounds.lowerBound)
        guard lowerBound < self.count else { return "" }

        let upperBound = min(bounds.upperBound, self.count)
        guard upperBound >= 0 else { return "" }

        let i = index(startIndex, offsetBy: lowerBound)
        let j = index(i, offsetBy: upperBound-lowerBound)

        return String(self[i..<j])
    }
}

答案 5 :(得分:1)

您可以将字符串转换为字符数组...

let aryChar = Array(myString)

然后您将获得所有阵列功能...

答案 6 :(得分:0)

extension String {

    subscript(bounds: CountableClosedRange<Int>) -> String {
        let lowerBound = max(0, bounds.lowerBound)
        guard lowerBound < self.count else { return "" }

        let upperBound = min(bounds.upperBound, self.count-1)
        guard upperBound >= 0 else { return "" }

        let i = index(startIndex, offsetBy: lowerBound)
        let j = index(i, offsetBy: upperBound-lowerBound)

        return String(self[i...j])
    }

    subscript(bounds: CountableRange<Int>) -> String {
        let lowerBound = max(0, bounds.lowerBound)
        guard lowerBound < self.count else { return "" }

        ***let upperBound = min(bounds.upperBound, self.count-1)***
        guard upperBound >= 0 else { return "" }

        let i = index(startIndex, offsetBy: lowerBound)
        let j = index(i, offsetBy: upperBound-lowerBound)

        return String(self[i..<j])
    }
}

答案 7 :(得分:0)

您收到此错误,因为带下标范围的结果是 Substring?不是Substring

您必须使用以下代码:

let myString: String = "foobar"
let mySubstring: Substring? = myString[1..<3]