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

Bar*_*nes 38 string swift swift4

在斯威夫特4,当我尝试采取我得到这个错误SubstringString使用标语法.

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

例如:

let myString: String = "foobar"
let mySubstring: Substring = myString[1..<3]
Run Code Online (Sandbox Code Playgroud)

两个问题:

  1. 我该如何解决这个错误?
  2. 错误中提到的"讨论文档评论"在哪里?

p-s*_*sun 63

  1. 如果你想在喜欢字符串使用标"palindrome"[1..<3]"palindrome"[1...3]使用这些扩展.

斯威夫特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])
    }
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特3

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

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

这是 Xcode错误引用的文档.

有关UTF-8和UTF-16等字符串编码的更多信息

  • 一切都很好,除了您应该只使用“bounds.upperBound”而不是“bounds.upperBound -bounds.lowerBound”作为“offsetBy”参数。 (2认同)

Cod*_*ent 19

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

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

let mySubstring: Substring = myString[1..<3]
Run Code Online (Sandbox Code Playgroud)

new 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)
Run Code Online (Sandbox Code Playgroud)

实际上,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)
Run Code Online (Sandbox Code Playgroud)


Bar*_*nes 14

  1. 我该如何解决这个错误?

此错误意味着您不能在下标格式中使用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]
Run Code Online (Sandbox Code Playgroud)
  1. 错误中提到的"讨论文档评论"在哪里?

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

  • 这里不要使用`encodedOffset`; 它不一定对应于字符,它(当前)对应于UTF-16代码单元(它只是*发生*为ASCII字符串的字符).例如,使用`let myString ="hello"`,`mySubstring`只是``(因为它用2个UTF-16代码单元编码).使用`let myString ="hello"`,下标会引发运行时错误,因为``用4个UTF-16代码单元编码.而不是使用`encodedOffset:`,使用`myString.index(myString.startIndex,offsetBy:2)`; 以人物为主题. (2认同)

小智 12

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

let aryChar = Array(myString)
Run Code Online (Sandbox Code Playgroud)

然后你会得到所有的数组功能......

  • 然后再转回String?这个解决方案是如此 (5认同)
  • 为了完整起见,地图也可以正常工作: "Hello World".map{$0}[6] // 'W' (2认同)

Jus*_*roz 6

基于p-sun的回答

雨燕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]
    }
}
Run Code Online (Sandbox Code Playgroud)

显着变化:

  • 现在是StringProtocol. 这使得采用者Substring也可以获得这些下标。
  • 结束索引是从边界的起始索引而不是字符串的开头偏移的。这可以防止从两次的开头开始遍历String。该index方法的复杂度为 O(n),其中 n 是相对于 i 的偏移量。