[解決済み] Swiftで範囲を作成する方法は?
質問
Objective-cでは、NSRangeを使用して範囲を作成します。
NSRange range;
では、Swiftで範囲を作るにはどうすればいいのでしょうか?
どのように解決するのですか?
Swift 4にアップデートしました。
Swift の範囲は、より複雑な
NSRange
よりも複雑で、Swift 3でも簡単ではありませんでした。この複雑さのいくつかの背後にある理由を理解しようとする場合、以下を読んでください。
この
と
この
. これらの作成方法と、どのような場合に使用するかを紹介します。
クローズド・レンジ
a...b
これは
範囲演算子
は Swift の範囲を作成し、その範囲には要素
a
と
要素
b
であっても
b
がその型に可能な最大値であっても(例えば
Int.max
). 閉じた範囲には2つのタイプがあります。
ClosedRange
と
CountableClosedRange
.
1.
ClosedRange
Swift のすべての範囲の要素は比較可能です (つまり、Comparable プロトコルに準拠します)。そのため、コレクションから範囲内の要素にアクセスすることができます。以下はその例です。
let myRange: ClosedRange = 1...3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c", "d"]
しかし
ClosedRange
は可算ではない(つまり、Sequenceプロトコルに準拠しない)。これはつまり
for
ループを使うことはできません。そのためには
CountableClosedRange
.
2.
CountableClosedRange
これは最後のものと似ていますが、今度は範囲も反復させることができます。
let myRange: CountableClosedRange = 1...3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c", "d"]
for index in myRange {
print(myArray[index])
}
ハーフオープンレンジ
a..<b
この範囲演算子には、要素
a
しかし
ではない
要素
b
. 上記と同様に、半開放型の範囲には2種類あります。
Range
と
CountableRange
.
1.
Range
と同様に
ClosedRange
と同じように、コレクションの要素にアクセスするために
Range
. 例
let myRange: Range = 1..<3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c"]
を反復処理することはできませんが、繰り返します。
Range
は比較可能なだけで、 stridable ではないからです。
2.
CountableRange
A
CountableRange
は反復を可能にする。
let myRange: CountableRange = 1..<3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c"]
for index in myRange {
print(myArray[index])
}
NSRange
この場合でも
NSRange
を使うことができます(Swiftで
属性付きの文字列
を作るときなど)、その作り方を知っておくと便利です。
let myNSRange = NSRange(location: 3, length: 2)
なお、これはロケーションと
長さ
であり、開始インデックスと終了インデックスではないことに注意してください。ここでの例は、Swift の範囲と同じような意味を持つ
3..<5
. しかし、型が異なるので、互換性はありません。
文字列を含む範囲
このような
...
と
..<
範囲演算子は、範囲を作成するための省略記法である。例えば
let myRange = 1..<3
同じ範囲を作るための長い手の方法は次のようになります。
let myRange = CountableRange<Int>(uncheckedBounds: (lower: 1, upper: 3)) // 1..<3
ここでインデックスの型が
Int
. ではうまくいきません。
String
なぜなら、文字列は文字でできていて、すべての文字が同じ大きさではないからです。(読む
この
をご覧ください)。例えば、「?」のような絵文字は、「b"」という文字よりも大きなスペースを必要とします。
NSRangeの問題
を試してみてください。
NSRange
と
NSString
を絵文字で入力すれば、私の言っていることがわかるでしょう。頭が痛くなる。
let myNSRange = NSRange(location: 1, length: 3)
let myNSString: NSString = "abcde"
myNSString.substring(with: myNSRange) // "bcd"
let myNSString2: NSString = "a????cde"
myNSString2.substring(with: myNSRange) // "????c" Where is the "d"!?
スマイリーフェイスは格納するために2つのUTF-16コードユニットを取るので、"d"を含まないという予想外の結果を出します。
Swift の解決策
このため、Swiftの文字列では
Range<String.Index>
ではなく
Range<Int>
. 文字列インデックスは、特定の文字列に基づいて計算され、絵文字や拡張書記素クラスタがあるかどうかを知ることができます。
例
var myString = "abcde"
let start = myString.index(myString.startIndex, offsetBy: 1)
let end = myString.index(myString.startIndex, offsetBy: 4)
let myRange = start..<end
myString[myRange] // "bcd"
myString = "a????cde"
let start2 = myString.index(myString.startIndex, offsetBy: 1)
let end2 = myString.index(myString.startIndex, offsetBy: 4)
let myRange2 = start2..<end2
myString[myRange2] // "????cd"
片側だけの範囲
a...
と
...b
そして
..<b
Swift 4では、少し簡略化されました。範囲の開始点または終了点が推論できるときはいつでも、それを省くことができます。
int
コレクションを反復処理するために、片側だけの整数範囲を使用することができます。以下はその例です。 ドキュメンテーション .
// iterate from index 2 to the end of the array
for name in names[2...] {
print(name)
}
// iterate from the beginning of the array to index 2
for name in names[...2] {
print(name)
}
// iterate from the beginning of the array up to but not including index 2
for name in names[..<2] {
print(name)
}
// the range from negative infinity to 5. You can't iterate forward
// over this because the starting point in unknown.
let range = ...5
range.contains(7) // false
range.contains(4) // true
range.contains(-1) // true
// You can iterate over this but it will be an infinate loop
// so you have to break out at some point.
let range = 5...
文字列
これはStringの範囲でも動作します。もし、範囲を
str.startIndex
または
str.endIndex
を片方の端につけても、そのままにしておくことができます。コンパイラはそれを推論する。
与えられた
var str = "Hello, playground"
let index = str.index(str.startIndex, offsetBy: 5)
let myRange = ..<index // Hello
インデックスからstr.endIndexに移動するためには
...
var str = "Hello, playground"
let index = str.index(str.endIndex, offsetBy: -10)
let myRange = index... // playground
こちらもご覧ください。
注意事項
- ある文字列で作成した範囲を別の文字列で使用することはできません。
- お分かりのように、文字列の範囲は Swift では面倒ですが、絵文字や他の Unicode のスカラーをよりよく扱うことができる可能性を持っています。
さらなる研究
関連
-
Swiftがエラーを報告。アボートトラップ:6
-
[解決済み] 使用しているSwiftのバージョンを確認するにはどうすればよいですか?
-
[解決済み] Python 3で「1000000000000000 in range(1000000000000001)」はなぜ速いのですか?
-
[解決済み] SwiftからObjective-Cのコードを呼び出すにはどうしたらいいですか?
-
[解決済み] Swiftで#pragmaマーク?
-
[解決済み] Swift Betaのパフォーマンス:配列のソート
-
[解決済み] Swiftベースのアプリケーションは、OS X 10.9/iOS 7以下でも動作しますか?
-
[解決済み] SwiftでUIAlertViewを作成するにはどうしたらいいですか?
-
[解決済み] SwiftでStringのサブストリングはどのように動作するか
-
[解決済み】Swift RangeからNSRange?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Swift Error fatal error: Optional value のアンラップ中に予期せず nil を発見した。
-
swift 4.0でのdispatch_async,dispatch_afterの使用について
-
[解決済み] SwiftでString.Indexはどのように動作するのか
-
[解決済み] プログラミング言語Swiftで文字列のn文字目を取得する
-
[解決済み] SwiftでStringのサブストリングはどのように動作するか
-
[解決済み] SwiftでUITextFieldとUITextViewのカーソル位置の取得と設定
-
[解決済み] Swiftで範囲を作成する方法は?
-
[解決済み] Swift: PREPROCESSORフラグ(`#if DEBUG`など)を使ってAPIキーを実装する方法とは?
-
[解決済み] Swift: インデックスで文字列配列を置換する
-
[解決済み] swiftにおける "precondition "と "assert "の違いとは?