私はSwift 3で私の古いコードと答えの一部を更新してきましたが、私がSwift StringsとIndexingに到達したとき、物事を理解するのは大変でした。
具体的には、次のことを試していました。
let str = "Hello, playground"
let prefixRange = str.startIndex..<str.startIndex.advancedBy(5) // error
2行目で次のエラーが発生した
'advancedBy'は使用できません。インデックスをnステップ進めるには、インデックスを生成したCharacterViewインスタンスで 'index(_:offsetBy :)'を呼び出します。
String
には以下のメソッドがあります。
str.index(after: String.Index)
str.index(before: String.Index)
str.index(String.Index, offsetBy: String.IndexDistance)
str.index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index)
最初は本当に混乱していたので、理解するまで遊んでみました。それらがどのように使用されているかを示すために、以下に回答を追加します。
以下の例はすべて使用しています
var str = "Hello, playground"
startIndex
およびendIndex
startIndex
は最初の文字のインデックスですendIndex
はインデックスですafter最後の文字。例
// character
str[str.startIndex] // H
str[str.endIndex] // error: after last character
// range
let range = str.startIndex..<str.endIndex
str[range] // "Hello, playground"
Swift 4's 片側範囲 を使用すると、範囲は次のいずれかの形式に簡略化できます。
let range = str.startIndex...
let range = ..<str.endIndex
わかりやすくするために、次の例では完全な形式を使用しますが、読みやすくするために、コードでは片側の範囲を使用することをお勧めします。
after
index(after: String.Index)
のように
after
は、与えられたインデックスの直後の文字のインデックスを参照します。例
// character
let index = str.index(after: str.startIndex)
str[index] // "e"
// range
let range = str.index(after: str.startIndex)..<str.endIndex
str[range] // "Ello, playground"
before
index(before: String.Index)
のように
before
は、与えられたインデックスの直前の文字のインデックスを参照します。例
// character
let index = str.index(before: str.endIndex)
str[index] // d
// range
let range = str.startIndex..<str.index(before: str.endIndex)
str[range] // Hello, playgroun
offsetBy
index(String.Index, offsetBy: String.IndexDistance)
のように
offsetBy
の値は正または負にすることができ、指定されたインデックスから始まります。タイプはString.IndexDistance
ですが、Int
を指定できます。例
// character
let index = str.index(str.startIndex, offsetBy: 7)
str[index] // p
// range
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end
str[range] // play
limitedBy
index(String.Index, offsetBy: String.IndexDistance, limitedBy: String.Index)
のように
limitedBy
は、オフセットによってインデックスが範囲外にならないようにするために役立ちます。これはバウンディングインデックスです。オフセットが制限を超える可能性があるので、このメソッドはOptionalを返します。インデックスが範囲外の場合はnil
を返します。例
// character
if let index = str.index(str.startIndex, offsetBy: 7, limitedBy: str.endIndex) {
str[index] // p
}
オフセットが77
ではなく7
であれば、if
ステートメントはスキップされます。
文字列にInt
インデックスを使うほうがmuch簡単です。すべての文字列に対して新しいString.Index
を作成しなければならないのは、Swiftの文字がボンネットの下ですべて同じ長さではないためです。単一のSwift Characterは、1つ、2つ、またはそれ以上のUnicodeコードポイントで構成されることがあります。したがって、各一意の文字列はその文字のインデックスを計算する必要があります。
この複雑さをIntインデックス拡張の背後に隠すことはおそらく可能ですが、私はそうすることを躊躇しています。実際に起こっていることを思い出すのは良いことです。
TableViewController内にUITextViewを作成します。私は関数textViewDidChangeを使い、それからreturn-key-inputをチェックしました。それからreturn-key-inputを検出した場合、returnキーの入力を削除してキーボードを消します。
func textViewDidChange(_ textView: UITextView) {
tableView.beginUpdates()
if textView.text.contains("\n"){
textView.text.remove(at: textView.text.index(before: textView.text.endIndex))
textView.resignFirstResponder()
}
tableView.endUpdates()
}