Bagaimana Anda menggunakan String.substringWithRange? (atau, bagaimana cara kerja Ranges di Swift?)

266

Saya belum bisa menemukan cara untuk mendapatkan substring dari Stringdalam Swift:

var str =Hello, playground”
func test(str: String) -> String {
 return str.substringWithRange( /* What goes here? */ )
}
test (str)

Saya tidak dapat membuat Range di Swift. Pelengkapan otomatis di Playground tidak super membantu - inilah yang disarankan:

return str.substringWithRange(aRange: Range<String.Index>)

Saya belum menemukan apa pun di Perpustakaan Referensi Standar Swift yang membantu. Inilah satu lagi tebakan liar:

return str.substringWithRange(Range(0, 1))

Dan ini:

let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)

Saya telah melihat jawaban lain ( Mencari indeks karakter dalam Swift String ) yang tampaknya menyarankan bahwa karena Stringmerupakan tipe jembatan untuk NSString, metode "lama" harus bekerja, tetapi tidak jelas bagaimana - misalnya, ini tidak berhasil juga ( tampaknya bukan sintaks yang valid):

let x = str.substringWithRange(NSMakeRange(0, 3))

Pikiran?

rampok
sumber
Apa maksud Anda ketika Anda mengatakan contoh terakhir tidak berhasil? Apakah itu menyebabkan kesalahan atau mengembalikan nilai yang tidak terduga?
67cherries
Tolong balas rdar: // 17158813 meminta notasi subskrip openradar.appspot.com/radar?id=6373877630369792
Rob Napier

Jawaban:

259

Anda dapat menggunakan metode substringWithRange. Dibutuhkan awal dan akhir String.Index.

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex)) //"Hello, playground"

Untuk mengubah indeks awal dan akhir, gunakan advancedBy (n).

var str = "Hello, playground"
str.substringWithRange(Range<String.Index>(start: str.startIndex.advancedBy(2), end: str.endIndex.advancedBy(-1))) //"llo, playgroun"

Anda juga masih dapat menggunakan metode NSString dengan NSRange, tetapi Anda harus memastikan bahwa Anda menggunakan NSString seperti ini:

let myNSString = str as NSString
myNSString.substringWithRange(NSRange(location: 0, length: 3))

Catatan: seperti yang disebutkan JanX2, metode kedua ini tidak aman dengan string unicode.

Connor
sumber
5
Ya. Untuk saat ini saya akan terus menjembatani ke NSString bila perlu. Tampaknya Swift's String masih belum lengkap
Connor
14
Ini tidak aman! Anda mengasumsikan bahwa indeks ke dalam String dan NSString dapat dipertukarkan. Bukan itu masalahnya. Indeks ke dalam String merujuk ke titik kode Unicode sementara indeks ke dalam NSString merujuk ke unit kode UTF-16! Cobalah dengan emoji.
JanX2
3
Harap dicatat bahwa Indeks menjadi String TIDAK merujuk pada poin kode Unicode lagi. Anggap saja sebagai referensi karakter yang dirasakan pengguna.
JanX2
2
Jadi apa jawaban yang benar di sini? Menelepon advanceberarti kita harus mengulanginya sepanjang string yang mungkin panjang. Tetapi membentuk NSRange dan menggunakan NSString secara eksplisit berbahaya? Apa yang tersisa
matt
1
Terima kasih, m8. Transisi ke Swift ini agak berantakan setelah 4 tahun hanya melakukan Objective-C.
Felipe
162

Cepat 2

Sederhana

let str = "My String"
let subStr = str[str.startIndex.advancedBy(3)...str.startIndex.advancedBy(7)]
//"Strin"

Cepat 3

let startIndex = str.index(str.startIndex, offsetBy: 3)
let endIndex = str.index(str.startIndex, offsetBy: 7)

str[startIndex...endIndex]       // "Strin"
str.substring(to: startIndex)    // "My "
str.substring(from: startIndex)  // "String"

Cepat 4

substring(to:)dan substring(from:)tidak digunakan lagi di Swift 4.

String(str[..<startIndex])    // "My "
String(str[startIndex...])    // "String"
String(str[startIndex...endIndex])    // "Strin"
Warif Akhand Rishi
sumber
2
INI. Jadi membingungkan bahwa Anda harus menemukan indeks Anda sebelum dapat menggunakannya. Tidak tahu mengapa saya butuh waktu lama untuk menyadari, tetapi terima kasih atas kontribusi Anda untuk jenis manusia.
Warpzit
1
Dalam operasi substring 4 cepat mengembalikan instance dari jenis Substring, bukan String. Perlu mengonversi hasilnya menjadi String untuk penyimpanan jangka panjang. biarkan newString = String (substring)
phnmnn
43

CATATAN: @airspeedswift membuat beberapa poin yang sangat mendalam tentang pertukaran dari pendekatan ini, khususnya dampak kinerja yang tersembunyi. String bukanlah beast yang sederhana, dan mencapai indeks tertentu mungkin membutuhkan waktu O (n), yang berarti sebuah loop yang menggunakan subskrip dapat berupa O (n ^ 2). Anda telah diperingatkan.

Anda hanya perlu menambahkan subscriptfungsi baru yang mengambil rentang dan gunakan advancedBy()untuk berjalan ke tempat yang Anda inginkan:

import Foundation

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let startIndex = self.startIndex.advancedBy(r.startIndex)
            let endIndex = startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

var s = "Hello, playground"

println(s[0...5]) // ==> "Hello,"
println(s[0..<5]) // ==> "Hello"

(Ini pasti harus menjadi bagian dari bahasa. Tolong ditipu rdar: // 17158813 )

Untuk bersenang-senang, Anda juga dapat menambahkan + operator ke indeks:

func +<T: ForwardIndex>(var index: T, var count: Int) -> T {
  for (; count > 0; --count) {
    index = index.succ()
  }
  return index
}

s.substringWithRange(s.startIndex+2 .. s.startIndex+5)

(Saya belum tahu apakah ini harus menjadi bagian dari bahasa atau tidak.)

Rob Napier
sumber
2
Kita mungkin harus bekerja dengan String.Index alih-alih indeks integer sebanyak mungkin karena alasan kinerja. Setiap konversi dari indeks integer menjadi sebuah String.Index perlu memproses string yang dicari.
JanX2
11
@AndrewDunn Ini bukan optimasi prematur. Setiap konversi dari indeks integer menjadi String.Index adalah O (n), bukan O (1)! Silakan baca komentar untuk advance<T>(…)di Swiftnamespace.
JanX2
1
Seluruh implementasi String dilakukan dengan menggunakan String.Index. Dalam hal ini, ini bukan optimasi sebanyak itu menjaga semuanya mudah. Harus berganti-ganti antara int dan String .Index bolak-balik di mana-mana akan menyebabkan kekacauan.
chakrit
@chakrit Hanya jika indeks yang perlu Anda gunakan belum bilangan bulat (bukan String.Indexes) yang sering terjadi. Daripada Anda bisa berharap semua metode penanganan string itu bekerja dengan Ints. Dan Anda terpaksa mengonversinya String.Indexesyang mengarah ke kekacauan yang Anda sebutkan.
Rasto
Pembaca yang tertarik harus melihat di ExSwift github.com/pNre/ExSwift
AsTeR
42

Pada saat saya sedang menulis, tidak ada ekstensi yang kompatibel dengan Swift 4.2 , jadi ini adalah salah satu yang mencakup semua kebutuhan yang dapat saya pikirkan:

extension String {
    func substring(from: Int?, to: Int?) -> String {
        if let start = from {
            guard start < self.count else {
                return ""
            }
        }

        if let end = to {
            guard end >= 0 else {
                return ""
            }
        }

        if let start = from, let end = to {
            guard end - start >= 0 else {
                return ""
            }
        }

        let startIndex: String.Index
        if let start = from, start >= 0 {
            startIndex = self.index(self.startIndex, offsetBy: start)
        } else {
            startIndex = self.startIndex
        }

        let endIndex: String.Index
        if let end = to, end >= 0, end < self.count {
            endIndex = self.index(self.startIndex, offsetBy: end + 1)
        } else {
            endIndex = self.endIndex
        }

        return String(self[startIndex ..< endIndex])
    }

    func substring(from: Int) -> String {
        return self.substring(from: from, to: nil)
    }

    func substring(to: Int) -> String {
        return self.substring(from: nil, to: to)
    }

    func substring(from: Int?, length: Int) -> String {
        guard length > 0 else {
            return ""
        }

        let end: Int
        if let start = from, start > 0 {
            end = start + length - 1
        } else {
            end = length - 1
        }

        return self.substring(from: from, to: end)
    }

    func substring(length: Int, to: Int?) -> String {
        guard let end = to, end > 0, length > 0 else {
            return ""
        }

        let start: Int
        if let end = to, end - length > 0 {
            start = end - length + 1
        } else {
            start = 0
        }

        return self.substring(from: start, to: to)
    }
}

Dan kemudian, Anda dapat menggunakan:

let string = "Hello,World!"

string.substring(from: 1, to: 7)memberi Anda: ello,Wo

string.substring(to: 7)memberi Anda: Hello,Wo

string.substring(from: 3)memberi Anda: lo,World!

string.substring(from: 1, length: 4)memberi Anda: ello

string.substring(length: 4, to: 7)memberi Anda: o,Wo

Diperbarui substring(from: Int?, length: Int)untuk mendukung mulai dari nol.

musim dingin
sumber
Bagaimana ini menangani emoji dan cluster grapheme yang diperluas? (Saya harus mengujinya sendiri tetapi saat ini tidak nyaman.)
Suragch
2
@ Suragch Ini menangani itu OK: "Hello😇😍😘😎📸📀💾∝ℵℶ≹".substring(from: 4, to: 14)memberi kita:o😇😍😘😎📸📀💾∝ℵℶ
musim dingin
Itu terlihat seperti karakter normal. Coba gunakan emoji seperti 👩‍👩‍👧‍👦 atau 🇨🇦🇺🇸🇲🇽
Supuhstar
31

SWIFT 2.0

sederhana:

let myString = "full text container"
let substring = myString[myString.startIndex..<myString.startIndex.advancedBy(3)] // prints: ful

SWIFT 3.0

let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful

SWIFT 4.0

Operasi Substring mengembalikan turunan dari jenis Substring, bukan String.

let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful

// Convert the result to a String for long-term storage.
let newString = String(substring)
PHNNN
sumber
4
Sayangnya, tidak lagi kompatibel dengan Swift 3 pada Xcode 8 beta 6
Ben Morrow
1
Bekerja untukku. Xcode 8, Swift 3. Bukan beta di Mac OS Sierra. text[text.startIndex..<text.index(text.startIndex, offsetBy: 2)]
Jose Ramirez
18

Ini jauh lebih sederhana daripada jawaban apa pun di sini, setelah Anda menemukan sintaks yang tepat.

Saya ingin mengambil [dan]

let myString = "[ABCDEFGHI]"
let startIndex = advance(myString.startIndex, 1) //advance as much as you like
let endIndex = advance(myString.endIndex, -1)
let range = startIndex..<endIndex
let myNewString = myString.substringWithRange( range )

hasilnya adalah "ABCDEFGHI", startIndex dan endIndex juga dapat digunakan di

let mySubString = myString.substringFromIndex(startIndex)

dan seterusnya!

PS: Seperti yang ditunjukkan dalam komentar, ada beberapa perubahan sintaks di swift 2 yang datang dengan xcode 7 dan iOS9!

Silakan lihat halaman ini

pengguna1700737
sumber
Ya, saya memiliki masalah yang sama dengan debugger yang tidak menampilkan string yang benar beberapa kali?
user1700737
saya punya string seperti ini / Tanggal (147410000000) /. Bagaimana saya bisa mendapatkan nilai alih-alih menentukan indeks. Saya perlu mendapatkan nilai menggunakan rangeOfString ("(") dan rangeOfString (")"). Hasilnya harus 147410000000. Cangkul bisa saya dapatkan
iPhone Guy
Itu tidak begitu sulit: var str = "/ Date (147410000000) /." var range = str.rangeOfString ("(")!. endIndex .. <str.rangeOfString (")") !. startIndex biarkan myNewString = str.substringWithRange (range)
user1700737
4
sejak advance(myString.endIndex, -1)sintaks Xcode 7 beta 6 telah berubah menjadimyString.endIndex.advancedBy(-1)
l --marc l
16

Misalnya untuk menemukan nama depan (hingga spasi pertama) dalam nama lengkap saya:

let name = "Joris Kluivers"

let start = name.startIndex
let end = find(name, " ")

if end {
    let firstName = name[start..end!]
} else {
    // no space found
}

startdan endbertipe di String.Indexsini dan digunakan untuk membuatRange<String.Index> dan digunakan di accessor subskrip (jika ruang ditemukan sama sekali dalam string asli).

Sulit untuk membuat String.Index langsung dari posisi bilangan bulat seperti yang digunakan dalam pos pembuka. Ini karena dalam nama saya setiap karakter akan memiliki ukuran yang sama dalam byte. Tetapi karakter yang menggunakan aksen khusus dalam bahasa lain dapat menggunakan beberapa byte lagi (tergantung pada pengkodean yang digunakan). Jadi byte apa yang harus merujuk integer?

Dimungkinkan untuk membuat yang baru String.Indexdari yang sudah ada menggunakan metode succdan predyang akan memastikan jumlah byte yang benar dilewati untuk sampai ke titik kode berikutnya dalam pengkodean. Namun dalam hal ini lebih mudah untuk mencari indeks spasi pertama dalam string untuk menemukan indeks akhir.

Joris Kluivers
sumber
16

Karena String adalah tipe jembatan untuk NSString, metode "lama" harus berfungsi, tetapi tidak jelas caranya - misalnya, ini tidak berfungsi baik (tampaknya bukan sintaks yang valid):

 let x = str.substringWithRange(NSMakeRange(0, 3))

Bagi saya, itu adalah bagian yang sangat menarik dari pertanyaan Anda. String adalah bridge ke NSString, sehingga sebagian besar metode NSString melakukan pekerjaan langsung pada String. Anda dapat menggunakannya secara bebas dan tanpa berpikir. Jadi, misalnya, ini berfungsi seperti yang Anda harapkan:

// delete all spaces from Swift String stateName
stateName = stateName.stringByReplacingOccurrencesOfString(" ", withString:"")

Tetapi, seperti yang sering terjadi, "Saya mendapat mojo saya bekerja tetapi itu tidak berhasil pada Anda." Anda kebetulan mengambil salah satu kasus langka di mana paralel bernama identik metode Swift ada , dan dalam kasus seperti itu, metode Swift menaungi metode Objective-C. Jadi, ketika Anda mengatakan str.substringWithRange, Swift menganggap maksud Anda metode Swift daripada metode NSString - dan kemudian Anda disemprot, karena metode Swift mengharapkan a Range<String.Index>, dan Anda tidak tahu cara membuat salah satunya.

Jalan keluar yang mudah adalah menghentikan Swift dari menaungi seperti ini, dengan melemparkan secara eksplisit:

let x = (str as NSString).substringWithRange(NSMakeRange(0, 3))

Perhatikan bahwa tidak ada pekerjaan tambahan yang signifikan yang terlibat di sini. "Cast" tidak berarti "convert"; String secara efektif merupakan NSString. Kami hanya memberi tahu Swift cara melihat variabel ini untuk keperluan satu baris kode ini.

Bagian yang sangat aneh dari semua ini adalah bahwa metode Swift, yang menyebabkan semua masalah ini, tidak didokumentasikan. Saya tidak tahu di mana itu didefinisikan; itu tidak di header NSString dan juga tidak di header Swift.

matt
sumber
Namun, saya sarankan mengajukan bug. Apple harus "memancing atau memotong umpan" - baik memberi kita cara untuk membangun Range<String.Index>, atau mengeluarkan metode tidak berdokumen ini dari cara kita.
matt
Sial - ini berguna. Terlepas dari apa yang dikatakan dokumentasi, saya tidak mengerti apa yang salah sampai saya membaca ini. Sekarang disortir :)
Jon M
13

Dalam penggunaan Xcode 7.0 baru

//: Playground - noun: a place where people can play

import UIKit

var name = "How do you use String.substringWithRange?"
let range = name.startIndex.advancedBy(0)..<name.startIndex.advancedBy(10)
name.substringWithRange(range)

//OUT:

masukkan deskripsi gambar di sini

Claudio Guirunas
sumber
2
.advancedBy(0) tidak diperlukan untuk startIndex.
Mat0
12

Jawaban singkatnya adalah bahwa ini sangat sulit di Swift sekarang. Firasat saya adalah bahwa masih ada banyak pekerjaan untuk Apple untuk dilakukan pada metode kenyamanan untuk hal-hal seperti ini.

String.substringWithRange()mengharapkan Range<String.Index>parameter, dan sejauh yang saya tahu tidak ada metode generator untuk String.Indextipe tersebut. Anda dapat memperoleh String.Indexnilai kembali dari aString.startIndexdan aString.endIndexdan menelepon .succ()atau.pred() pada mereka, tapi itu gila.

Bagaimana dengan ekstensi pada kelas String yang membutuhkan waktu lama Int?

extension String {
    subscript (r: Range<Int>) -> String {
        get {
            let subStart = advance(self.startIndex, r.startIndex, self.endIndex)
            let subEnd = advance(subStart, r.endIndex - r.startIndex, self.endIndex)
            return self.substringWithRange(Range(start: subStart, end: subEnd))
        }
    }
    func substring(from: Int) -> String {
        let end = countElements(self)
        return self[from..<end]
    }
    func substring(from: Int, length: Int) -> String {
        let end = from + length
        return self[from..<end]
    }
}

let mobyDick = "Call me Ishmael."
println(mobyDick[8...14])             // Ishmael

let dogString = "This 🐶's name is Patch."
println(dogString[5..<6])               // 🐶
println(dogString[5...5])              // 🐶
println(dogString.substring(5))        // 🐶's name is Patch.
println(dogString.substring(5, length: 1))   // 🐶

Memperbarui: Swift beta 4 menyelesaikan masalah di bawah ini!

Seperti berdiri [dalam beta 3 dan sebelumnya], bahkan string Swift-asli memiliki beberapa masalah dengan penanganan karakter Unicode. Ikon anjing di atas berfungsi, tetapi yang berikut tidak:

let harderString = "1:1️⃣"
for character in harderString {
    println(character)
}

Keluaran:

1
:
1
️
⃣
Nate Cook
sumber
1
Aneh, inti kelas Swift sepertinya kurang banyak fungsi dasar. Saya tidak bisa berpikir Apple ingin kita terus menerus referensi kelas Foundation untuk melakukan tugas-tugas sederhana.
bluedevil2k
1
Sama sekali. Perlu diingat bahwa Swift pada dasarnya dikembangkan dalam kegelapan, dan setiap orang memiliki definisi berbeda tentang "tugas sederhana" - Saya yakin kita melihat beberapa iterasi cepat pada masalah ini.
Nate Cook
@ JanX2 - Terima kasih, Anda sepenuhnya benar. Menjembatani mulus NSStringmembuat saya berpikir saya hanya menggunakan Stringmetode Swift-asli , karena saya tidak menggunakan myString as NSStringpanggilan apa pun .
Nate Cook
Ada beberapa bug Unicode dalam penanganan string asli Swift sekarang juga: lihat catatan saya di akhir.
Nate Cook
@NateCook Bisakah Anda mengajukan radar untuk masalah itu?
JanX2
11

Anda dapat menggunakan ekstensi ini untuk meningkatkan substringWithRange

Cepat 2.3

extension String
{   
    func substringWithRange(start: Int, end: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if end < 0 || end > self.characters.count
        {
            print("end index \(end) out of bounds")
            return ""
        }
        let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(end))
        return self.substringWithRange(range)
    }

    func substringWithRange(start: Int, location: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if location < 0 || start + location > self.characters.count
        {
            print("end index \(start + location) out of bounds")
            return ""
        }
        let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(start + location))
        return self.substringWithRange(range)
    }
}

Cepat 3

extension String
{
    func substring(start: Int, end: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if end < 0 || end > self.characters.count
        {
            print("end index \(end) out of bounds")
            return ""
        }
        let startIndex = self.characters.index(self.startIndex, offsetBy: start)
        let endIndex = self.characters.index(self.startIndex, offsetBy: end)
        let range = startIndex..<endIndex

        return self.substring(with: range)
    }

    func substring(start: Int, location: Int) -> String
    {
        if (start < 0 || start > self.characters.count)
        {
            print("start index \(start) out of bounds")
            return ""
        }
        else if location < 0 || start + location > self.characters.count
        {
            print("end index \(start + location) out of bounds")
            return ""
        }
        let startIndex = self.characters.index(self.startIndex, offsetBy: start)
        let endIndex = self.characters.index(self.startIndex, offsetBy: start + location)
        let range = startIndex..<endIndex

        return self.substring(with: range)
    }
}

Pemakaian:

let str = "Hello, playground"

let substring1 = str.substringWithRange(0, end: 5) //Hello
let substring2 = str.substringWithRange(7, location: 10) //playground
ChikabuZ
sumber
7

Kode Contoh untuk cara mendapatkan substring di Swift 2.0

(i) Substring dari indeks awal

Memasukkan:-

var str = "Swift is very powerful language!"
print(str)

str = str.substringToIndex(str.startIndex.advancedBy(5))
print(str)

Keluaran:-

Swift is very powerful language!
Swift

(ii) Substring dari indeks tertentu

Memasukkan:-

var str = "Swift is very powerful language!"
print(str)

str = str.substringFromIndex(str.startIndex.advancedBy(6)).substringToIndex(str.startIndex.advancedBy(2))
print(str)

Keluaran:-

Swift is very powerful language!
is

Saya harap ini akan membantu Anda!

Umang Kothari
sumber
7

Solusi mudah dengan kode kecil.

Buat ekstensi yang mencakup subString dasar yang dimiliki hampir semua bahasa lainnya:

extension String {
    func subString(start: Int, end: Int) -> String {
        let startIndex = self.index(self.startIndex, offsetBy: start)
        let endIndex = self.index(startIndex, offsetBy: end)

        let finalString = self.substring(from: startIndex)
        return finalString.substring(to: endIndex)
    }
}

Cukup panggil ini dengan

someString.subString(start: 0, end: 6)
Oliver Dixon
sumber
1
Parameter 'end' sebenarnya berarti panjang di sini jadi saya pikir itu harus diubah namanya menjadi itu.
Jovan Jovanovski
Saya pikir menggunakan panjang agak membingungkan. Ini sebenarnya adalah 'akhir' di mana Anda ingin menjadi subString, bukan panjang sebenarnya hasil subString.
Oliver Dixon
6

Ini bekerja di taman bermain saya :)

String(seq: Array(str)[2...4])
patrykens
sumber
Sebenarnya ini lebih efisien daripada meneleponadvance
Erik Aigner
2
Ini tidak berfungsi di taman bermain Xcode 7 (Swift 2) saya, tetapi ini tidak ... 'var str = "Hello, playground"' String (Array (str.characters) [7]) // "p" String (Array ( str.characters) [7 ... 10]) // "play" String (Array (str.characters) [7 .. <10]) // "pla"
Vince O'Sullivan
6

Diperbarui untuk Xcode 7. Menambahkan ekstensi String:

Menggunakan:

var chuck: String = "Hello Chuck Norris"
chuck[6...11] // => Chuck

Penerapan:

extension String {

    /**
     Subscript to allow for quick String substrings ["Hello"][0...1] = "He"
     */
    subscript (r: Range<Int>) -> String {
        get {
            let start = self.startIndex.advancedBy(r.startIndex)
            let end = self.startIndex.advancedBy(r.endIndex - 1)
            return self.substringWithRange(start..<end)
        }
    }

}
Firo
sumber
4

coba ini di taman bermain

var str:String = "Hello, playground"

let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,8))

itu akan memberi Anda "ello, p"

Namun di mana ini menjadi sangat menarik adalah bahwa jika Anda membuat indeks terakhir lebih besar dari string di taman bermain itu akan menunjukkan string apa pun yang Anda tetapkan setelah str: o

Range () tampaknya merupakan fungsi generik sehingga perlu mengetahui tipe yang dihadapinya.

Anda juga harus memberikan string yang sebenarnya Anda minati di taman bermain karena tampaknya menyimpan semua sengatan secara berurutan dengan nama variabel mereka sesudahnya.

Begitu

var str:String = "Hello, playground"

var str2:String = "I'm the next string"

let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,49))

memberikan "ello, playground str I'm string str2 berikutnya"

berfungsi bahkan jika str2 didefinisikan dengan let

:)

Peter Roberts
sumber
Saya setuju itu verbose dibandingkan dengan Objective-C, namun semuanya cocok pada satu baris yang merupakan bonus.
Peter Roberts
Yah masih ada satu baris yang hilang yang benar-benar mencetak substring mengingat rentang yang Anda hitung. Saya suka beberapa solusi lain yang membuat ekstensi kelas String menggunakan logika Anda, tetapi dalam ekstensi. Itulah akhirnya solusi yang saya gunakan.
Roderic Campbell
Mereka telah memperbaiki bug di mana Anda dapat melampaui akhir string. Sekarang Anda hanya dapat memberi nilai hingga str.endIndex
Peter Roberts
4

Rob Napier sudah memberikan jawaban yang bagus menggunakan subskrip. Tapi saya merasakan satu kekurangan dalam hal itu karena tidak ada pemeriksaan untuk kondisi di luar batas. Ini bisa cenderung macet. Jadi saya memodifikasi ekstensi dan ini dia

extension String {
    subscript (r: Range<Int>) -> String? { //Optional String as return value
        get {
            let stringCount = self.characters.count as Int
            //Check for out of boundary condition
            if (stringCount < r.endIndex) || (stringCount < r.startIndex){
                return nil
            }
            let startIndex = self.startIndex.advancedBy(r.startIndex)

            let endIndex = self.startIndex.advancedBy(r.endIndex - r.startIndex)

            return self[Range(start: startIndex, end: endIndex)]
        }
    }
}

Output di bawah

var str2 = "Hello, World"

var str3 = str2[0...5]
//Hello,
var str4 = str2[0..<5]
//Hello
var str5 = str2[0..<15]
//nil

Jadi saya sarankan untuk selalu memeriksa jika biarkan

if let string = str[0...5]
{
    //Manipulate your string safely
}
iPrabu
sumber
Anda memiliki bug di sana - endIndex harus startIndex yang dikembangkan oleh endIndex saja, bukan jarak antara indeks.
Aviad Ben Dov
3

Di Swift3

Sebagai contoh: variabel "Duke James Thomas", kita perlu mendapatkan "James".

let name = "Duke James Thomas"
let range: Range<String.Index> = name.range(of:"James")!
let lastrange: Range<String.Index> = img.range(of:"Thomas")!
var middlename = name[range.lowerBound..<lstrange.lowerBound]
print (middlename)
Sandu
sumber
2

Mengambil halaman dari Rob Napier, saya mengembangkan Common String Extensions ini , dua di antaranya adalah:

subscript (r: Range<Int>) -> String
{
    get {
        let startIndex = advance(self.startIndex, r.startIndex)
        let endIndex = advance(self.startIndex, r.endIndex - 1)

        return self[Range(start: startIndex, end: endIndex)]
    }
}

func subString(startIndex: Int, length: Int) -> String
{
    var start = advance(self.startIndex, startIndex)
    var end = advance(self.startIndex, startIndex + length)
    return self.substringWithRange(Range<String.Index>(start: start, end: end))
}

Pemakaian:

"Awesome"[3...7] //"some"
"Awesome".subString(3, length: 4) //"some"
Albert Bori
sumber
Anda dapat menggunakan Rangesebagai ganti Range<String.Index>terima kasih untuk mengetik inferensi.
Dan Rosenstark
2

Ini adalah cara Anda mendapatkan rentang dari string:

var str = "Hello, playground"

let startIndex = advance(str.startIndex, 1)
let endIndex = advance(startIndex, 8)
let range = startIndex..<endIndex
let substr = str[range] //"ello, pl"

Poin kuncinya adalah bahwa Anda melewati serangkaian nilai dari tipe String.Index (ini adalah apa yang mengembalikan muka) bukan bilangan bulat.

Alasan mengapa ini diperlukan, adalah bahwa string di Swift tidak memiliki akses acak (karena panjang variabel karakter Unicode pada dasarnya). Anda juga tidak bisa melakukannyastr[1] . String.Index dirancang untuk bekerja dengan struktur internal mereka.

Anda dapat membuat ekstensi dengan subskrip, yang melakukan ini untuk Anda, jadi Anda bisa melewati serangkaian bilangan bulat (lihat misalnya jawaban Rob Napier ).

Ixx
sumber
2

Saya mencoba membuat sesuatu Pythonic.

Semua subskrip di sini hebat, tetapi saat saya benar-benar membutuhkan sesuatu yang sederhana biasanya ketika saya ingin menghitung dari belakang, misalnya string.endIndex.advancedBy(-1)

Ini mendukung nilnilai, untuk indeks awal dan akhir, di mana nilberarti indeks pada 0 untuk awal, string.characters.countuntuk akhir.

extension String {
    var subString: (Int?) -> (Int?) -> String {
        return { (start) in
            { (end) in
                let startIndex = start ?? 0 < 0 ? self.endIndex.advancedBy(start!) : self.startIndex.advancedBy(start ?? 0)
                let endIndex = end ?? self.characters.count < 0 ? self.endIndex.advancedBy(end!) : self.startIndex.advancedBy(end ?? self.characters.count)

                return startIndex > endIndex ? "" : self.substringWithRange(startIndex ..< endIndex)
            }
        }
    }
}

let dog = "Dog‼🐶"
print(dog.subString(nil)(-1)) // Dog!!

EDIT

Solusi yang lebih elegan:

public extension String {
    struct Substring {
        var start: Int?
        var string: String

        public subscript(end: Int?) -> String {
            let startIndex = start ?? 0 < 0 ? string.endIndex.advancedBy(start!) : string.startIndex.advancedBy(start ?? 0)
            let endIndex = end ?? string.characters.count < 0 ? string.endIndex.advancedBy(end!) : string.startIndex.advancedBy(end ?? string.characters.count)

            return startIndex > endIndex ? "" : string.substringWithRange(startIndex ..< endIndex)
        }
    }

    public subscript(start: Int?) -> Substring {
        return Substring(start: start, string: self)
    }
}

let dog = "Dog‼🐶"
print(dog[nil][-1]) // Dog!!
funct7
sumber
1

Pertama buat rentang, lalu substring. Anda dapat menggunakan fromIndex..<toIndexsintaks seperti:

let range = fullString.startIndex..<fullString.startIndex.advancedBy(15) // 15 first characters of the string
let substring = fullString.substringWithRange(range)
Johannes
sumber
1

berikut adalah contoh untuk mendapatkan video-Id saja .ie (6oL687G0Iso) dari seluruh URL dengan cepat

let str = "https://www.youtube.com/watch?v=6oL687G0Iso&list=PLKmzL8Ib1gsT-5LN3V2h2H14wyBZTyvVL&index=2"
var arrSaprate = str.componentsSeparatedByString("v=")
let start = arrSaprate[1]
let rangeOfID = Range(start: start.startIndex,end:start.startIndex.advancedBy(11))
let substring = start[rangeOfID]
print(substring)
Hardik Thakkar
sumber
1
let startIndex = text.startIndex
var range = startIndex.advancedBy(1) ..< text.endIndex.advancedBy(-4)
let substring = text.substringWithRange(range)

Sampel lengkap bisa Anda lihat di sini

Svitlana
sumber
0

Yah, saya punya masalah yang sama dan diselesaikan dengan fungsi "bridgeToObjectiveC ()":

var helloworld = "Hello World!"
var world = helloworld.bridgeToObjectiveC().substringWithRange(NSMakeRange(6,6))
println("\(world)") // should print World!

Harap perhatikan bahwa dalam contoh, substringWithRange bersamaan dengan NSMakeRange ambil bagian dari string mulai dari indeks 6 (karakter "W") dan berakhir pada indeks 6 + 6 posisi di depan (karakter "!")

Bersulang.

sittisal
sumber
Saya benci ini, tetapi itu adalah satu-satunya hal yang tampaknya bekerja untuk saya dalam Beta 4.
Roderic Campbell
0

Anda dapat menggunakan salah satu metode substring dalam ekstensi Swift String yang saya tulis https://bit.ly/JString .

var string = "hello"
var sub = string.substringFrom(3) // or string[3...5]
println(sub)// "lo"
William Falcon
sumber
0

Jika Anda memiliki NSRange, menjembatani untuk NSStringbekerja dengan lancar. Sebagai contoh, saya melakukan beberapa pekerjaan dengan UITextFieldDelegatedan saya dengan cepat ingin menghitung nilai string baru ketika ditanya apakah harus mengganti rentang.

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
    println("Got new string: ", newString)
}
joslinm
sumber
0

Ekstensi sederhana untuk String:

extension String {

    func substringToIndex(index: Int) -> String {
        return self[startIndex...startIndex.advancedBy(min(index, characters.count - 1))]
    }
}
Bartłomiej Semańczyk
sumber
0

Jika Anda tidak peduli dengan kinerja ... ini mungkin solusi paling ringkas di Swift 4

extension String {
    subscript(range: CountableClosedRange<Int>) -> String {
        return enumerated().filter{$0.offset >= range.first! && $0.offset < range.last!}
            .reduce(""){$0 + String($1.element)}
    }
}

Ini memungkinkan Anda untuk melakukan sesuatu seperti ini:

let myStr = "abcd"
myStr[0..<2] // produces "ab"
Jiachen Ren
sumber