Swift 4では、添え字構文を使用してSubstring
のString
を取得しようとすると、このエラーが発生します。
'subscript'は使用できません:CountableClosedRangeを使用して文字列に添え字を付けることはできません。説明についてはドキュメントのコメントを参照してください
例えば:
let myString: String = "foobar"
let mySubstring: Substring = myString[1..<3]
2つの質問:
"palindrome"[1..<3]
や"palindrome"[1...3]
などの文字列に添え字を使用する場合は、これらの拡張機能を使用します。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]
に置き換えます。
String.Index
で他の文字列エンコーディングを指定できます。これはドキュメントです Xcodeエラーが参照しています。
質問(および自己回答)には2つの問題があります。
Int
を使用した文字列の添字付けは、Swiftの標準ライブラリでは使用できませんでした。 Swiftが存在する限り、このコードは無効です。
let mySubstring: Substring = myString[1..<3]
新しいString.Index(encodedOffset: )
は、UTF-16(16ビット)エンコーディングでインデックスを返します。 Swiftの文字列はExtended Grapheme Clusterを使用します。これは、8〜64ビットで文字を保存できます。絵文字は非常に優れたデモンストレーションに役立ちます。
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)
実際、Swift 4でString.Index
を取得しても、良くも悪くもまったく変わりません。
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)
- このエラーを解決するにはどうすればよいですか?
このエラーは、添え字形式で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]
- エラーで言及された「議論のためのドキュメンテーションコメント」はどこにありますか?
GitHubのSwift Standard LibraryリポジトリのUnavailableStringAPIs.Swift.gybというファイルにあるロックされたファイリングキャビネットの底にあり、使用されていないトイレに立ち往生しているドアに「ヒョウに気をつけて」というサインがあります。 リンク
p-Sunの回答 に基づく
Swift 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
の開始から2回の移動が防止されます。 index
メソッドはO(n)です。nはiからのオフセットです。p-Sun's と Justin Oroz の両方の答えに基づいて、文字列の開始と終了を超える無効なインデックスから保護する2つの拡張機能があります(これらの拡張機能は、文字列の再スキャンも回避します範囲の終わりでインデックスを見つけるためだけに最初から):
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])
}
}
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])
}
}
範囲付きの添字の結果がSubstring
ではなくSubstring?
であるため、このエラーが発生します。
次のコードを使用する必要があります。
let myString: String = "foobar"
let mySubstring: Substring? = myString[1..<3]