Untuk apa Anda membutuhkan jangkauan? String Swift digunakan Range<String.Index>, tapi terkadang perlu untuk bekerja dengan NSStringdan NSRange, jadi beberapa konteks lainnya akan berguna. - Tapi lihat stackoverflow.com/questions/24092884/… .
Martin R
Jawaban:
258
Diperbarui untuk Swift 4
Rentang Swift lebih kompleks daripada NSRange, dan tidak menjadi lebih mudah di Swift 3. Jika Anda ingin mencoba memahami alasan di balik beberapa kerumitan ini, baca ini dan ini . Saya hanya akan menunjukkan cara membuatnya dan kapan Anda mungkin menggunakannya.
Rentang Tertutup: a...b
Operator rentang ini membuat rentang Swift yang menyertakan elemen adan elemen b, meskipun bnilai maksimum yang mungkin untuk suatu tipe (suka Int.max). Ada dua jenis rentang tertutup: ClosedRangedan CountableClosedRange.
1. ClosedRange
Elemen dari semua rentang di Swift sebanding (yaitu, mereka sesuai dengan protokol Comparable). Itu memungkinkan Anda mengakses elemen dalam rentang dari koleksi. Berikut ini contohnya:
let myRange:ClosedRange=1...3let myArray =["a","b","c","d","e"]
myArray[myRange]//["b","c","d"]
Namun, a ClosedRangetidak dapat dihitung (yaitu, tidak sesuai dengan protokol Urutan). Itu berarti Anda tidak dapat mengulang elemen dengan forloop. Untuk itu Anda membutuhkan file CountableClosedRange.
2. CountableClosedRange
Ini mirip dengan yang terakhir kecuali sekarang rentangnya juga dapat diulang.
let myRange:CountableClosedRange=1...3let myArray =["a","b","c","d","e"]
myArray[myRange]// ["b", "c", "d"]
for index in myRange {
print(myArray[index])}
Rentang Setengah Terbuka: a..<b
Operator rentang ini menyertakan elemen atetapi bukan elemen b. Seperti di atas, ada dua jenis rentang setengah terbuka: Rangedan CountableRange.
1. Range
Seperti halnya ClosedRange, Anda dapat mengakses elemen koleksi dengan file Range. Contoh:
let myRange:Range=1..<3let myArray =["a","b","c","d","e"]
myArray[myRange]//["b","c"]
Namun, sekali lagi, Anda tidak dapat mengulangi a Rangekarena hanya dapat dibandingkan, tidak dapat dilangkah.
2. CountableRange
A CountableRangememungkinkan iterasi.
let myRange:CountableRange=1..<3let myArray =["a","b","c","d","e"]
myArray[myRange]// ["b", "c"]
for index in myRange {
print(myArray[index])}
NSRange
Anda NSRangekadang-kadang masih dapat (harus) menggunakan di Swift (saat membuat string yang diatribusikan , misalnya), jadi akan sangat membantu untuk mengetahui cara membuatnya.
let myNSRange =NSRange(location:3, length:2)
Perhatikan bahwa ini adalah lokasi dan panjang , bukan indeks awal dan indeks akhir. Contoh di sini serupa artinya dengan rentang Swift 3..<5. Namun, karena jenisnya berbeda, mereka tidak dapat dipertukarkan.
Berkisar dengan Strings
Operator ...dan ..<jangkauan adalah cara cepat untuk membuat rentang. Sebagai contoh:
let myRange =1..<3
Cara tangan panjang untuk membuat rentang yang sama adalah
let myRange =CountableRange<Int>(uncheckedBounds:(lower:1, upper:3))//1..<3
Anda dapat melihat bahwa tipe indeks di sini adalah Int. Itu tidak berhasil String, karena String terbuat dari Karakter dan tidak semua karakter memiliki ukuran yang sama. (Baca ini untuk info lebih lanjut.) Emoji seperti 😀, misalnya, membutuhkan lebih banyak tempat daripada huruf "b".
Masalah dengan NSRange
Cobalah bereksperimen dengan NSRangedan NSStringdengan emoji dan Anda akan melihat apa yang saya maksud. Sakit kepala.
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"Whereis the "d"!?
Wajah tersenyum membutuhkan dua unit kode UTF-16 untuk disimpan, sehingga memberikan hasil yang tidak diharapkan dari tidak menyertakan "d".
Solusi Cepat
Karena itu, dengan Swift Strings yang Anda gunakan Range<String.Index>, bukan Range<Int>. Indeks String dihitung berdasarkan string tertentu sehingga mengetahui apakah ada emoji atau cluster grafik yang diperluas.
Di Swift 4 hal disederhanakan sedikit. Kapan pun titik awal atau akhir suatu rentang dapat disimpulkan, Anda dapat membiarkannya.
Int
Anda dapat menggunakan rentang integer satu sisi untuk mengulang koleksi. Berikut beberapa contoh dari dokumentasinya .
// 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...
Tali
Ini juga berfungsi dengan rentang String. Jika Anda membuat rentang dengan str.startIndexatau str.endIndexdi salah satu ujung, Anda bisa membiarkannya. Kompilator akan menyimpulkannya.
Diberikan
var str ="Hello, playground"let index = str.index(str.startIndex, offsetBy:5)let myRange =..<index //Hello
Anda dapat beralih dari indeks ke str.endIndex dengan menggunakan ...
var str ="Hello, playground"let index = str.index(str.endIndex, offsetBy:-10)let myRange = index...// playground
Anda tidak dapat menggunakan rentang yang Anda buat dengan satu string pada string berbeda.
Seperti yang Anda lihat, rentang String menyebalkan di Swift, tetapi mereka memungkinkan untuk menangani emoji dan skalar Unicode lainnya dengan lebih baik.
Komentar saya berkaitan dengan subbagian "Masalah dengan NSRange". NSStringmenyimpan karakternya secara internal dalam pengkodean UTF-16. Skalar unicode penuh adalah 21-bit. Karakter wajah yang menyeringai ( U+1F600) tidak dapat disimpan dalam satu unit kode 16-bit, sehingga tersebar 2. NSRangedihitung berdasarkan unit kode 16-bit. Dalam contoh ini, 3 unit kode kebetulan hanya mewakili 2 karakter
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)
Saya melihat mereka memiliki "Range" Datatype. Jadi bagaimana saya bisa menggunakannya?
vichhai
@vichhai Bisakah Anda menjelaskan lebih lanjut di mana Anda ingin menggunakan?
Dharmbir Singh
Seperti dalam obyektif c: kisaran NSRange;
vichhai
1
Saya merasa mengejutkan bahwa, bahkan di Swift 4, masih tidak ada cara asli sederhana untuk mengekspresikan rentang String menggunakan Int. Satu-satunya metode String yang memungkinkan Anda menyediakan Int sebagai cara untuk mendapatkan substring menurut range adalah prefixdan suffix.
Berguna untuk memiliki beberapa utilitas konversi, sehingga kita dapat berbicara seperti NSRange saat berbicara dengan String. Berikut adalah utilitas yang mengambil lokasi dan panjang, seperti NSRange, dan mengembalikan Range<String.Index>:
Misalnya, "hello".range(0,1)"adalah Range<String.Index>merangkul karakter pertama "hello". Sebagai bonus, saya mengizinkan lokasi negatif: "hello".range(-1,1)"adalah Range<String.Index>pelukan karakter terakhir "hello".
Berguna juga untuk mengonversi a Range<String.Index>menjadi NSRange, untuk saat-saat ketika Anda harus berbicara dengan Cocoa (misalnya, dalam menangani rentang atribut NSAttributedString). Swift 4 menyediakan cara asli untuk melakukan itu:
let nsrange =NSRange(range,in:s)//where s is the string
Dengan demikian kita dapat menulis utilitas lain di mana kita pergi langsung dari lokasi dan panjang String ke NSRange:
let nsRange =NSRange(location: someInt, length: someInt)
seperti dalam
let myNSString = bigTOTPCode asNSString//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
Range<String.Index>
, tapi terkadang perlu untuk bekerja denganNSString
danNSRange
, jadi beberapa konteks lainnya akan berguna. - Tapi lihat stackoverflow.com/questions/24092884/… .Jawaban:
Diperbarui untuk Swift 4
Rentang Swift lebih kompleks daripada
NSRange
, dan tidak menjadi lebih mudah di Swift 3. Jika Anda ingin mencoba memahami alasan di balik beberapa kerumitan ini, baca ini dan ini . Saya hanya akan menunjukkan cara membuatnya dan kapan Anda mungkin menggunakannya.Rentang Tertutup:
a...b
Operator rentang ini membuat rentang Swift yang menyertakan elemen
a
dan elemenb
, meskipunb
nilai maksimum yang mungkin untuk suatu tipe (sukaInt.max
). Ada dua jenis rentang tertutup:ClosedRange
danCountableClosedRange
.1.
ClosedRange
Elemen dari semua rentang di Swift sebanding (yaitu, mereka sesuai dengan protokol Comparable). Itu memungkinkan Anda mengakses elemen dalam rentang dari koleksi. Berikut ini contohnya:
Namun, a
ClosedRange
tidak dapat dihitung (yaitu, tidak sesuai dengan protokol Urutan). Itu berarti Anda tidak dapat mengulang elemen denganfor
loop. Untuk itu Anda membutuhkan fileCountableClosedRange
.2.
CountableClosedRange
Ini mirip dengan yang terakhir kecuali sekarang rentangnya juga dapat diulang.
Rentang Setengah Terbuka:
a..<b
Operator rentang ini menyertakan elemen
a
tetapi bukan elemenb
. Seperti di atas, ada dua jenis rentang setengah terbuka:Range
danCountableRange
.1.
Range
Seperti halnya
ClosedRange
, Anda dapat mengakses elemen koleksi dengan fileRange
. Contoh:Namun, sekali lagi, Anda tidak dapat mengulangi a
Range
karena hanya dapat dibandingkan, tidak dapat dilangkah.2.
CountableRange
A
CountableRange
memungkinkan iterasi.NSRange
Anda
NSRange
kadang-kadang masih dapat (harus) menggunakan di Swift (saat membuat string yang diatribusikan , misalnya), jadi akan sangat membantu untuk mengetahui cara membuatnya.Perhatikan bahwa ini adalah lokasi dan panjang , bukan indeks awal dan indeks akhir. Contoh di sini serupa artinya dengan rentang Swift
3..<5
. Namun, karena jenisnya berbeda, mereka tidak dapat dipertukarkan.Berkisar dengan Strings
Operator
...
dan..<
jangkauan adalah cara cepat untuk membuat rentang. Sebagai contoh:Cara tangan panjang untuk membuat rentang yang sama adalah
Anda dapat melihat bahwa tipe indeks di sini adalah
Int
. Itu tidak berhasilString
, karena String terbuat dari Karakter dan tidak semua karakter memiliki ukuran yang sama. (Baca ini untuk info lebih lanjut.) Emoji seperti 😀, misalnya, membutuhkan lebih banyak tempat daripada huruf "b".Masalah dengan NSRange
Cobalah bereksperimen dengan
NSRange
danNSString
dengan emoji dan Anda akan melihat apa yang saya maksud. Sakit kepala.Wajah tersenyum membutuhkan dua unit kode UTF-16 untuk disimpan, sehingga memberikan hasil yang tidak diharapkan dari tidak menyertakan "d".
Solusi Cepat
Karena itu, dengan Swift Strings yang Anda gunakan
Range<String.Index>
, bukanRange<Int>
. Indeks String dihitung berdasarkan string tertentu sehingga mengetahui apakah ada emoji atau cluster grafik yang diperluas.Contoh
Rentang satu sisi:
a...
dan...b
dan..<b
Di Swift 4 hal disederhanakan sedikit. Kapan pun titik awal atau akhir suatu rentang dapat disimpulkan, Anda dapat membiarkannya.
Int
Anda dapat menggunakan rentang integer satu sisi untuk mengulang koleksi. Berikut beberapa contoh dari dokumentasinya .
Tali
Ini juga berfungsi dengan rentang String. Jika Anda membuat rentang dengan
str.startIndex
ataustr.endIndex
di salah satu ujung, Anda bisa membiarkannya. Kompilator akan menyimpulkannya.Diberikan
Anda dapat beralih dari indeks ke str.endIndex dengan menggunakan
...
Lihat juga:
Catatan
Pelajaran lanjutan
sumber
NSString
menyimpan karakternya secara internal dalam pengkodean UTF-16. Skalar unicode penuh adalah 21-bit. Karakter wajah yang menyeringai (U+1F600
) tidak dapat disimpan dalam satu unit kode 16-bit, sehingga tersebar 2.NSRange
dihitung berdasarkan unit kode 16-bit. Dalam contoh ini, 3 unit kode kebetulan hanya mewakili 2 karakterXcode 8 beta 2 • Swift 3
Xcode 7 • Swift 2.0
atau sederhananya
sumber
kembali ...
sumber
Gunakan seperti ini
Hasil: Halo
sumber
Saya merasa mengejutkan bahwa, bahkan di Swift 4, masih tidak ada cara asli sederhana untuk mengekspresikan rentang String menggunakan Int. Satu-satunya metode String yang memungkinkan Anda menyediakan Int sebagai cara untuk mendapatkan substring menurut range adalah
prefix
dansuffix
.Berguna untuk memiliki beberapa utilitas konversi, sehingga kita dapat berbicara seperti NSRange saat berbicara dengan String. Berikut adalah utilitas yang mengambil lokasi dan panjang, seperti NSRange, dan mengembalikan
Range<String.Index>
:Misalnya,
"hello".range(0,1)"
adalahRange<String.Index>
merangkul karakter pertama"hello"
. Sebagai bonus, saya mengizinkan lokasi negatif:"hello".range(-1,1)"
adalahRange<String.Index>
pelukan karakter terakhir"hello"
.Berguna juga untuk mengonversi a
Range<String.Index>
menjadi NSRange, untuk saat-saat ketika Anda harus berbicara dengan Cocoa (misalnya, dalam menangani rentang atribut NSAttributedString). Swift 4 menyediakan cara asli untuk melakukan itu:Dengan demikian kita dapat menulis utilitas lain di mana kita pergi langsung dari lokasi dan panjang String ke NSRange:
sumber
Jika ada yang ingin membuat objek NSRange bisa dibuat sebagai:
ini akan menciptakan jarak dengan posisi 0 dan panjang 5
sumber
sumber
Saya membuat ekstensi berikut:
contoh penggunaan:
sumber
Anda bisa menggunakan seperti ini
seperti dalam
sumber
Aku ingin melakukan ini:
Tapi sayangnya, saya tidak bisa menulis subskrip saya sendiri karena yang dibenci mengambil ruang nama.
Namun kami dapat melakukan ini:
Cukup tambahkan ini ke proyek Anda:
sumber