Objective-cでは、NSRangeを使用して範囲を作成しています
NSRange range;
それではSwiftで範囲を作成するにはどうすればいいですか?
Swift 4用に更新された
Swiftの範囲はNSRange
name__よりも複雑で、Swift 3ではそれほど簡単にはなりませんでした。この複雑さの背後にある理由を理解したい場合は、 this および this 。I ')を読んでください。それらを作成する方法とそれらを使用する可能性があるときにだけあなたに示すでしょう。
a...b
この 範囲演算子 は、a
name__が(Int.max
のような)型で可能な最大値であっても、要素b
name__とelement b
name__の両方を含むSwift範囲を作成します。閉じた範囲にはClosedRange
name__とCountableClosedRange
name__の2種類があります。
ClosedRange
name__Swiftのすべての範囲の要素は同等です(つまり、それらはComparableプロトコルに準拠しています)。それはあなたがコレクションから範囲内の要素にアクセスすることを可能にします。これが一例です。
let myRange: ClosedRange = 1...3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c", "d"]
ただし、ClosedRange
name__はカウントできません(つまり、Sequenceプロトコルに準拠していません)。つまり、for
name__ループで要素を反復処理することはできません。そのためにはCountableClosedRange
name__が必要です。
CountableClosedRange
name__これは最後のものと似ていますが、今度は範囲を繰り返すこともできます。
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
name__が含まれますが、notelement b
name__が含まれます。上記のように、2つの異なるタイプの半開き範囲があります:Range
name__およびCountableRange
name__。
Range
name__ClosedRange
name__と同様に、Range
name__を使用してコレクションの要素にアクセスできます。例:
let myRange: Range = 1..<3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c"]
ただし、ここでもRange
name__を反復処理することはできません。これは比較可能なものであり、厳密ではないためです。
CountableRange
name__CountableRange
name__は反復を許可します。
let myRange: CountableRange = 1..<3
let myArray = ["a", "b", "c", "d", "e"]
myArray[myRange] // ["b", "c"]
for index in myRange {
print(myArray[index])
}
SwiftではNSRange
name__を( 属性付き文字列 など)を作成するときに)使用することができる(しなければならない)ので、作成方法を知っておくと便利です。
let myNSRange = NSRange(location: 3, length: 2)
これはlocationであり、lengthであり、開始インデックスと終了インデックスではないことに注意してください。この例はSwiftの範囲3..<5
と意味が似ています。ただし、種類が異なるため、互換性はありません。
...
および..<
の範囲演算子は範囲を作成するための簡単な方法です。例えば:
let myRange = 1..<3
同じ範囲を作成するための手間のかかる方法は、
let myRange = CountableRange<Int>(uncheckedBounds: (lower: 1, upper: 3)) // 1..<3
ここでのインデックスタイプはInt
name__です。ただし、String
name__では文字列が文字で構成され、すべての文字が同じサイズではないため、これは機能しません。 (詳細は this を読んでください。)例えば、????のような絵文字は、文字 "b"よりも多くのスペースを取ります。
NSRangeの問題
NSRange
name__とNSString
name__を絵文字で試してみると、私の言っていることがわかります。頭痛。
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 Solution
このため、Swift Stringsでは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
片側整数範囲を使用してコレクションを反復処理できます。これは documentation )の例です。
// 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...
文字列
これは文字列範囲でも機能します。一方の端に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
注意事項
Xcode 8 beta 2•Swift
let myString = "Hello World"
let myRange = myString.startIndex..<myString.index(myString.startIndex, offsetBy: 5)
let mySubString = myString.substring(with: myRange) // Hello
Xcode 7•Swift 2.
let myString = "Hello World"
let myRange = Range<String.Index>(start: myString.startIndex, end: myString.startIndex.advancedBy(5))
let mySubString = myString.substringWithRange(myRange) // Hello
あるいは単に
let myString = "Hello World"
let myRange = myString.startIndex..<myString.startIndex.advancedBy(5)
let mySubString = myString.substringWithRange(myRange) // Hello
(1 .. <10)
返します...
範囲= 1 .. <10
こんな感じ
var start = str.startIndex // Start at the string's start index
var end = advance(str.startIndex, 5) // Take start index and advance 5 characters forward
var range: Range<String.Index> = Range<String.Index>(start: start,end: end)
let firstFiveDigit = str.substringWithRange(range)
print(firstFiveDigit)
出力:こんにちは
誰でもNSRangeオブジェクトを作成したい場合は、次のように作成できます。
let range: NSRange = NSRange.init(location: 0, length: 5)
これにより、位置0、長さ5の範囲が作成されます。
Swift 4でも、Intを使用してStringの範囲を表現するための単純なネイティブの方法がまだないことは驚くべきことです。範囲を指定して部分文字列を取得する方法としてIntを指定できるようにする唯一のStringメソッドは、prefix
とsuffix
です。
Stringと話すときにNSRangeのように話すことができるように、いくつかの変換ユーティリティを用意しておくと便利です。これは、NSRangeのように位置と長さを取得し、Range<String.Index>
を返すユーティリティです。
func range(_ start:Int, _ length:Int) -> Range<String.Index> {
let i = self.index(start >= 0 ? self.startIndex : self.endIndex,
offsetBy: start)
let j = self.index(i, offsetBy: length)
return i..<j
}
たとえば、"hello".range(0,1)"
は、Range<String.Index>
の最初の文字を含む"hello"
です。ボーナスとして、私は否定的な位置を許しました:"hello".range(-1,1)"
はRange<String.Index>
の最後の文字を受け入れる"hello"
です。
Cocoaと対話しなければならないとき(たとえば、NSAttributedString属性の範囲を扱う場合)には、Range<String.Index>
をNSRangeに変換することも便利です。 Swift 4はそれを行うためのネイティブな方法を提供します。
let nsrange = NSRange(range, in:s) // where s is the string
したがって、Stringの位置と長さからNSRangeに直接移動する別のユーティリティを書くことができます。
extension String {
func nsRange(_ start:Int, _ length:Int) -> NSRange {
return NSRange(self.range(start,length), in:self)
}
}
私は以下の拡張子を作成しました:
extension String {
func substring(from from:Int, to:Int) -> String? {
if from<to && from>=0 && to<self.characters.count {
let rng = self.startIndex.advancedBy(from)..<self.startIndex.advancedBy(to)
return self.substringWithRange(rng)
} else {
return nil
}
}
}
使用例
print("abcde".substring(from: 1, to: 10)) //nil
print("abcde".substring(from: 2, to: 4)) //Optional("cd")
print("abcde".substring(from: 1, to: 0)) //nil
print("abcde".substring(from: 1, to: 1)) //nil
print("abcde".substring(from: -1, to: 1)) //nil
こんな感じで使えます
let nsRange = NSRange(location: someInt, length: someInt)
のように
let myNSString = bigTOTPCode as NSString //12345678
let firstDigit = myNSString.substringWithRange(NSRange(location: 0, length: 1)) //1
let secondDigit = myNSString.substringWithRange(NSRange(location: 1, length: 1)) //2
let thirdDigit = myNSString.substringWithRange(NSRange(location: 2, length: 4)) //3456
func replace(input: String, start: Int,lenght: Int, newChar: Character) -> String {
var chars = Array(input.characters)
for i in start...lenght {
guard i < input.characters.count else{
break
}
chars[i] = newChar
}
return String(chars)
}