Dapatkan karakter n dari string dalam bahasa pemrograman Swift

419

Bagaimana saya bisa mendapatkan karakter n dari string? Saya mencoba braket ( []) accessor tanpa hasil.

var string = "Hello, world!"

var firstChar = string[0] // Throws error

GALAT: 'subskrip' tidak tersedia: tidak dapat subskrip dengan String dengan Int, lihat komentar dokumentasi untuk diskusi

Mohsen
sumber
1
Pesan kesalahan "tidak dapat mensubtitusi String dengan Int, lihat komentar dokumentasi untuk diskusi" tampaknya merujuk ke github.com/apple/swift/blob/master/stdlib/public/core/…
andrewdotn
gunakan var firstChar = string.index(string.startIndex, offsetBy: 0)sebagai gantinya
Sazzad Hissain Khan
@SazzadHissainKhan ini akan menghasilkan indeks string, bukan karakter. Btw kenapa tidak sederhana saja string.startIndex? Untuk karakter pertama string[string.startIndex] atau sederhananya string.first. Perhatikan bahwa pendekatan pertama yang perlu Anda periksa apakah string kosong pertama yang kedua mengembalikan opsional
Leo Dabus

Jawaban:

567

Perhatian: Silakan lihat jawaban Leo Dabus untuk implementasi yang tepat untuk Swift 4 dan Swift 5.

Cepat 4 atau lebih baru

Itu Substring jenis diperkenalkan di Swift 4 untuk membuat substring lebih cepat dan lebih efisien dengan berbagi penyimpanan dengan string asli, sehingga ini apa fungsi subscript harus kembali.

Cobalah di sini

extension StringProtocol {
    subscript(offset: Int) -> Character { self[index(startIndex, offsetBy: offset)] }
    subscript(range: Range<Int>) -> SubSequence {
        let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
        return self[startIndex..<index(startIndex, offsetBy: range.count)]
    }
    subscript(range: ClosedRange<Int>) -> SubSequence {
        let startIndex = index(self.startIndex, offsetBy: range.lowerBound)
        return self[startIndex..<index(startIndex, offsetBy: range.count)]
    }
    subscript(range: PartialRangeFrom<Int>) -> SubSequence { self[index(startIndex, offsetBy: range.lowerBound)...] }
    subscript(range: PartialRangeThrough<Int>) -> SubSequence { self[...index(startIndex, offsetBy: range.upperBound)] }
    subscript(range: PartialRangeUpTo<Int>) -> SubSequence { self[..<index(startIndex, offsetBy: range.upperBound)] }
}

Untuk mengonversikannya Substringmenjadi String, Anda cukup melakukannya String(string[0..2]), tetapi Anda hanya harus melakukannya jika Anda berencana untuk menjaga agar substring tetap ada. Kalau tidak, akan lebih efisien jika menyimpannya Substring.

Alangkah baiknya jika seseorang dapat menemukan cara yang baik untuk menggabungkan dua ekstensi ini menjadi satu. Saya mencoba memperluas StringProtocol tanpa keberhasilan, karena indexmetode itu tidak ada di sana. Catatan: Jawaban ini sudah diedit, sudah diterapkan dengan benar dan sekarang berfungsi untuk substring juga. Pastikan untuk menggunakan rentang yang valid untuk menghindari tabrakan saat berlangganan jenis StringProtocol Anda. Untuk berlangganan dengan rentang yang tidak akan macet dengan nilai di luar rentang, Anda dapat menggunakan implementasi ini


Mengapa ini bukan bawaan?

Pesan kesalahan mengatakan "lihat komentar dokumentasi untuk diskusi" . Apple memberikan penjelasan berikut dalam file UnavailableStringAPIs.swift :

String langganan dengan bilangan bulat tidak tersedia.

Konsep " ikarakter th dalam sebuah string" memiliki interpretasi berbeda di berbagai pustaka dan komponen sistem. Penafsiran yang benar harus dipilih sesuai dengan kasus penggunaan dan API yang terlibat, sehingga String tidak dapat disubkripsikan dengan bilangan bulat.

Swift menyediakan beberapa cara berbeda untuk mengakses data karakter yang disimpan di dalam string.

  • String.utf8adalah kumpulan unit kode UTF-8 dalam string. Gunakan API ini saat mengonversi string ke UTF-8. Sebagian besar POSIX API memproses string dalam hal unit kode UTF-8.

  • String.utf16adalah kumpulan unit kode UTF-16 dalam string. Sebagian besar Cocoa dan Cocoa touch string memproses string dalam hal unit kode UTF-16. Misalnya, instance yang NSRangedigunakan dengan NSAttributedStringdan NSRegularExpressionmenyimpan offset dan panjang substring dalam hal unit kode UTF-16.

  • String.unicodeScalarsadalah koleksi skalar Unicode. Gunakan API ini saat Anda melakukan manipulasi data karakter tingkat rendah.

  • String.characters adalah kumpulan cluster grapheme yang diperluas, yang merupakan perkiraan karakter yang dirasakan pengguna.

Perhatikan bahwa saat memproses string yang berisi teks yang dapat dibaca manusia, pemrosesan karakter-demi-karakter harus dihindari sejauh mungkin. Gunakan tingkat tinggi lokal-sensitif algoritma Unicode bukan, misalnya, String.localizedStandardCompare(), String.localizedLowercaseString, String.localizedStandardRangeOfString()dll

aleclarson
sumber
4
Cannot find an overload for 'advance' that accepts an argument list of type '(String.Index, T)'... String.Indexdan Inttidak kompatibel.
7
Jika Anda melihat Cannot subscript a value of type 'String'...periksa jawaban ini: stackoverflow.com/a/31265316/649379
SoftDesigner
24
Ketika saya mencoba menggunakan ini, saya mengerti Ambiguous use of 'subscript'.
jowie
18
PERINGATAN! Ekstensi di bawah ini sangat tidak efisien. Setiap kali string diakses dengan integer, fungsi O (n) untuk memajukan indeks awal dijalankan. Menjalankan loop linier di dalam loop linier lain berarti ini untuk loop secara tidak sengaja O (n2) - karena panjang string meningkat, waktu yang dibutuhkan loop ini meningkat secara kuadratik. Alih-alih melakukan itu Anda bisa menggunakan koleksi string karakter.
ignaciohugog
2
fatal error: Can't form a Character from an empty String
Devin B
341

Cepat 5.2

let str = "abcdef"
str[1 ..< 3] // returns "bc"
str[5] // returns "f"
str[80] // returns ""
str.substring(fromIndex: 3) // returns "def"
str.substring(toIndex: str.length - 2) // returns "abcd"

Anda perlu menambahkan ekstensi String ini ke proyek Anda (ini sepenuhnya diuji):

extension String {

    var length: Int {
        return count
    }

    subscript (i: Int) -> String {
        return self[i ..< i + 1]
    }

    func substring(fromIndex: Int) -> String {
        return self[min(fromIndex, length) ..< length]
    }

    func substring(toIndex: Int) -> String {
        return self[0 ..< max(0, toIndex)]
    }

    subscript (r: Range<Int>) -> String {
        let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)),
                                            upper: min(length, max(0, r.upperBound))))
        let start = index(startIndex, offsetBy: range.lowerBound)
        let end = index(start, offsetBy: range.upperBound - range.lowerBound)
        return String(self[start ..< end])
    }
}

Meskipun Swift selalu memiliki solusi untuk masalah ini (tanpa ekstensi String, yang saya berikan di bawah), saya tetap akan melakukannya sangat menyarankan menggunakan ekstensi. Mengapa? Karena itu menyelamatkan saya dari puluhan jam migrasi yang menyakitkan dari versi awal Swift, di mana sintaksis String mengubah hampir setiap rilis, tetapi yang perlu saya lakukan adalah memperbarui implementasi ekstensi sebagai lawan refactoring seluruh proyek. Tentukan pilihanmu.

let str = "Hello, world!"
let index = str.index(str.startIndex, offsetBy: 4)
str[index] // returns Character 'o'

let endIndex = str.index(str.endIndex, offsetBy:-2)
str[index ..< endIndex] // returns String "o, worl"

String(str.suffix(from: index)) // returns String "o, world!"
String(str.prefix(upTo: index)) // returns String "Hell"
nalexn
sumber
ubah range.upperBound - range.lowerBoundkerange.count
Leo Dabus
Itu bukan bagian dari pertanyaan awal, tapi ... alangkah baiknya jika tugas ini didukung juga. Misalnya, s [i] = "a" :).
Chris Prince
2
Saya percaya dengan subskripsi Swift 4.2 tidak tersedia lagi. Saya mendapat pesan kesalahan: 'subskrip' tidak tersedia: tidak bisa subskrip dengan String dengan Int, lihat komentar dokumentasi untuk diskusi
C0D3
2
@ChrisPrinceextension StringProtocol where Self: RangeReplaceableCollection { subscript(offset: Int) -> Element { get { return self[index(startIndex, offsetBy: offset)] } set { let start = index(startIndex, offsetBy: offset) replaceSubrange(start..<index(after: start), with: [newValue]) } } }
Leo Dabus
Ini harusnya merupakan fungsi
bawaan
150

Saya baru saja menemukan solusi yang rapi ini

var firstChar = Array(string)[0]
Jens Wirth
sumber
2
Ini adalah solusi cepat yang bagus untuk kasus (umum) di mana Anda tahu Anda memiliki string yang dikodekan UTF8 atau ASCII. Pastikan bahwa string tidak akan pernah berada dalam pengkodean yang menggunakan lebih dari satu byte.
Jeff Hay
48
Itu tampaknya sangat tidak efisien karena Anda menyalin seluruh string hanya untuk mendapatkan karakter pertama. Gunakan string [string. startIndex] bukannya 0 seperti yang Sulthan tunjukkan.
Bjorn
6
Buka gulungan string: var firstChar = Array(string!)[0]Kalau tidak akan dikatakanadd arrayLiteral
Mohammad Zaid Pathan
2
Saya tidak percaya ini bersih, karena sebenarnya ini adalah putaran. Saya tidak yakin inisialisasi mana dalam Array yang digunakan pertama menyebabkan ini terjadi (dan saya berasumsi itu adalah initializer SequenceType yang menyebabkannya untuk mengumpulkan karakter string sebagai komponen individu untuk Array). Ini tidak eksplisit sama sekali dan dapat diperbaiki di masa depan tanpa tipe casting. Ini juga tidak berfungsi jika Anda menggunakan singkatan untuk array melalui [string] .first. Solusi @ Sulthan paling baik digunakan menggunakan nilai indeks yang dipanggang. Jauh lebih jelas tentang apa yang terjadi di sini.
TheCodingArt
2
Wow, kesalahan segmen kompiler!
Frank
124

Tidak ada pengindeksan menggunakan bilangan bulat, hanya menggunakan String.Index. Sebagian besar dengan kompleksitas linier. Anda juga dapat membuat rentang dari String.Indexdan menggunakan substring.

Swift 3.0

let firstChar = someString[someString.startIndex]
let lastChar = someString[someString.index(before: someString.endIndex)]
let charAtIndex = someString[someString.index(someString.startIndex, offsetBy: 10)]

let range = someString.startIndex..<someString.index(someString.startIndex, offsetBy: 10)
let substring = someString[range]

Swift 2.x

let firstChar = someString[someString.startIndex]
let lastChar = someString[someString.endIndex.predecessor()]
let charAtIndex = someString[someString.startIndex.advanceBy(10)]

let range = someString.startIndex..<someString.startIndex.advanceBy(10)
let subtring = someString[range]

Perhatikan bahwa Anda tidak dapat menggunakan indeks (atau rentang) yang dibuat dari satu string ke string lain

let index10 = someString.startIndex.advanceBy(10)

//will compile
//sometimes it will work but sometimes it will crash or result in undefined behaviour
let charFromAnotherString = anotherString[index10]
Sulthan
sumber
7
Stringindeks unik untuk sebuah string. Ini karena string yang berbeda mungkin memiliki UTF-16 multi-unit yang berbeda Charactersdan / atau pada posisi yang berbeda sehingga indeks unit UTF-16 tidak akan cocok, dapat melampaui batas atau titik di dalam UTF-16 multi-unit Character.
zaph
@Zaph Itu sudah jelas.
Sulthan
3
Menjelaskan mengapa Anda mengatakan: "kadang-kadang akan crash atau menghasilkan perilaku yang tidak terdefinisi". Mungkin lebih baik untuk mengatakan jangan lakukan itu karena ...
zaph
1
@Sulthan ..sekarang ..<(dalam tugas Anda untuk range)
Aaron Brager
3
@CajunLuke Saya tahu ini sudah lama sejak Anda mengirim komentar ini, tetapi lihat jawaban ini . Anda dapat menggunakanvar lastChar = string[string.endIndex.predecessor()]
David L
122

Xcode 11 β€’ Swift 5.1

Anda dapat memperluas StringProtocol untuk membuat subskrip juga tersedia untuk substring:

extension StringProtocol {
    subscript(_ offset: Int)                     -> Element     { self[index(startIndex, offsetBy: offset)] }
    subscript(_ range: Range<Int>)               -> SubSequence { prefix(range.lowerBound+range.count).suffix(range.count) }
    subscript(_ range: ClosedRange<Int>)         -> SubSequence { prefix(range.lowerBound+range.count).suffix(range.count) }
    subscript(_ range: PartialRangeThrough<Int>) -> SubSequence { prefix(range.upperBound.advanced(by: 1)) }
    subscript(_ range: PartialRangeUpTo<Int>)    -> SubSequence { prefix(range.upperBound) }
    subscript(_ range: PartialRangeFrom<Int>)    -> SubSequence { suffix(Swift.max(0, count-range.lowerBound)) }
}

extension LosslessStringConvertible {
    var string: String { .init(self) }
}

extension BidirectionalCollection {
    subscript(safe offset: Int) -> Element? {
        guard !isEmpty, let i = index(startIndex, offsetBy: offset, limitedBy: index(before: endIndex)) else { return nil }
        return self[i]
    }
}

Pengujian

let test = "Hello USA πŸ‡ΊπŸ‡Έ!!! Hello Brazil πŸ‡§πŸ‡·!!!"
test[safe: 10]   // "πŸ‡ΊπŸ‡Έ"
test[11]   // "!"
test[10...]   // "πŸ‡ΊπŸ‡Έ!!! Hello Brazil πŸ‡§πŸ‡·!!!"
test[10..<12]   // "πŸ‡ΊπŸ‡Έ!"
test[10...12]   // "πŸ‡ΊπŸ‡Έ!!"
test[...10]   // "Hello USA πŸ‡ΊπŸ‡Έ"
test[..<10]   // "Hello USA "
test.first   // "H"
test.last    // "!"

// Subscripting the Substring
 test[...][...3]  // "Hell"

// Note that they all return a Substring of the original String.
// To create a new String from a substring
test[10...].string  // "πŸ‡ΊπŸ‡Έ!!! Hello Brazil πŸ‡§πŸ‡·!!!"
Leo Dabus
sumber
Bolehkah saya bertanya apa itu "diri [indeks (startIndex, offsetBy: i)]"? Dan bagaimana cara "mandiri [i]" bekerja?
allenlinli
1
Halo Leo, terima kasih atas solusinya! Saya baru saja (hari ini) beralih dari Swift 2.3 ke 3 dan subskrip solusi Anda (rentang: Rentang <Int>) memberikan kesalahan "Argumen ekstra 'terbatas oleh panggilan'". Menurut Anda apa yang salah?
Ahmet AkkΓΆk
@ AhmetAkkΓΆk Anda yakin tidak mengubah kode?
Leo Dabus
1
@ Leo ternyata saya tidak mengonversi seluruh proyek tetapi pada aplikasi bukan ekstensi, saya sudah mengulangi proses untuk kedua aplikasi dan ekstensi dan itu bekerja OK sekarang. Bantuan Anda sangat kami hargai!
Ahmet AkkΓΆk
ini kode yang sangat rumit. Apa keuntungan dari melakukan return String(Array(characters)[range])di Swift 3?
Dan Rosenstark
69

Cepat 4

let str = "My String"

String pada indeks

let index = str.index(str.startIndex, offsetBy: 3)
String(str[index])    // "S"

Substring

let startIndex = str.index(str.startIndex, offsetBy: 3)
let endIndex = str.index(str.startIndex, offsetBy: 7)
String(str[startIndex...endIndex])     // "Strin"

Pertama dan karakter

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[..<startIndex])    // "My "

Terakhir n karakter

let startIndex = str.index(str.startIndex, offsetBy: 3)
String(str[startIndex...])    // "String"

Swift 2 dan 3

str = "My String"

** String Pada Indeks **

Cepat 2

let charAtIndex = String(str[str.startIndex.advancedBy(3)])  // charAtIndex = "S"

Cepat 3

str[str.index(str.startIndex, offsetBy: 3)]

SubString dariIndex keIndex

Cepat 2

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

Cepat 3

str[str.index(str.startIndex, offsetBy: 3)...str.index(str.startIndex, offsetBy: 7)]

Pertama dan karakter

let first2Chars = String(str.characters.prefix(2)) // first2Chars = "My"

Terakhir n karakter

let last3Chars = String(str.characters.suffix(3)) // last3Chars = "ing"
Warif Akhand Rishi
sumber
24

Swift 2.0 pada Xcode 7 GM Seed

var text = "Hello, world!"

let firstChar = text[text.startIndex.advancedBy(0)] // "H"

Untuk karakter ke-n, ganti 0 dengan n-1.

Edit: Swift 3.0

text[text.index(text.startIndex, offsetBy: 0)]


nb ada cara-cara sederhana untuk meraih karakter tertentu dalam string

misalnya let firstChar = text.characters.first

Matt Le Fleur
sumber
23

Jika Anda melihat Cannot subscript a value of type 'String'...menggunakan ekstensi ini:

Cepat 3

extension String {
    subscript (i: Int) -> Character {
        return self[self.characters.index(self.startIndex, offsetBy: i)]
    }

    subscript (i: Int) -> String {
        return String(self[i] as Character)
    }

    subscript (r: Range<Int>) -> String {
        let start = index(startIndex, offsetBy: r.lowerBound)
        let end = index(startIndex, offsetBy: r.upperBound)
        return self[start..<end]
    }

    subscript (r: ClosedRange<Int>) -> String {
        let start = index(startIndex, offsetBy: r.lowerBound)
        let end = index(startIndex, offsetBy: r.upperBound)
        return self[start...end]
    }
}

Cepat 2.3

extension String {
    subscript(integerIndex: Int) -> Character {
        let index = advance(startIndex, integerIndex)
        return self[index]
    }

    subscript(integerRange: Range<Int>) -> String {
        let start = advance(startIndex, integerRange.startIndex)
        let end = advance(startIndex, integerRange.endIndex)
        let range = start..<end
        return self[range]
    }
}

Sumber: http://oleb.net/blog/2014/07/swift-strings/

SoftDesigner
sumber
19

Solusi Swift 2.2:

Ekstensi berikut berfungsi di Xcode 7, ini adalah kombinasi dari solusi ini dan konversi sintaks Swift 2.0.

extension String {
    subscript(integerIndex: Int) -> Character {
        let index = startIndex.advancedBy(integerIndex)
        return self[index]
    }

    subscript(integerRange: Range<Int>) -> String {
        let start = startIndex.advancedBy(integerRange.startIndex)
        let end = startIndex.advancedBy(integerRange.endIndex)
        let range = start..<end
        return self[range]
    }
}
Dan Beaulieu
sumber
14

Kelas string cepat tidak memberikan kemampuan untuk mendapatkan karakter pada indeks tertentu karena dukungan asli untuk karakter UTF. Panjang variabel karakter UTF dalam memori membuat melompat langsung ke karakter tidak mungkin. Itu berarti Anda harus secara manual mengulangi string setiap kali.

Anda dapat memperluas String untuk menyediakan metode yang akan berulang melalui karakter sampai indeks yang Anda inginkan

extension String {
    func characterAtIndex(index: Int) -> Character? {
        var cur = 0
        for char in self {
            if cur == index {
                return char
            }
            cur++
        }
        return nil
    }
}

myString.characterAtIndex(0)!
drewag
sumber
3
Anda sudah dapat mengulang-ulang string: untuk huruf dalam "foo" {println (letter)}
Doobeh
@Doobeh yang saya maksud adalah loop through dan mengembalikan karakter yang sebenarnya seperti dalam edit saya di atas
drewag
bagus! Lucu bagaimana Anda bisa mengulanginya, tetapi tidak melalui indeks. Perasaan Swift pythonic tetapi dengan tepi yang lebih keras.
Doobeh
Saya menemukan menggunakan myString.bridgeToObjectiveC().characterAtIndex(0)atau (string as NSString ).characterAtIndex(0) mengembalikan nilai Int karakter
markhunte
4
Jangan menggunakan NSStringmetode untuk mengakses karakter individu dari Swift-asli String- keduanya menggunakan mekanisme penghitungan yang berbeda, sehingga Anda akan mendapatkan hasil yang tidak dapat diprediksi dengan karakter Unicode yang lebih tinggi. Metode pertama harus aman (setelah bug Unicode Swift ditangani).
Nate Cook
11

Sebagai catatan tambahan, ada beberapa fungsi yang dapat diterapkan langsung ke representasi rantai karakter String, seperti ini:

var string = "Hello, playground"
let firstCharacter = string.characters.first // returns "H"
let lastCharacter = string.characters.last // returns "d"

Hasilnya bertipe Character, tetapi Anda bisa melemparkannya ke String.

Atau ini:

let reversedString = String(string.characters.reverse())
// returns "dnuorgyalp ,olleH" 

:-)

FrΓ©dΓ©ric Adda
sumber
11

Cepat 4

String(Array(stringToIndex)[index]) 

Ini mungkin cara terbaik untuk menyelesaikan masalah ini satu kali. Anda mungkin ingin melemparkan String sebagai array terlebih dahulu, dan kemudian melemparkan hasilnya sebagai String lagi. Jika tidak, Karakter akan dikembalikan sebagai ganti String.

Contoh String(Array("HelloThere")[1])akan mengembalikan "e" sebagai String.

(Array("HelloThere")[1] akan mengembalikan "e" sebagai Karakter.

Swift tidak memungkinkan Strings diindeks seperti array, tetapi ini menyelesaikan pekerjaan dengan gaya kasar.

Harsh G.
sumber
1
Menggandakan seluruh isi string ke lokasi memori lain adalah kontra-performan, terutama untuk string besar. Kita seharusnya tidak memerlukan alokasi memori tambahan untuk tugas-tugas sederhana seperti akses memori langsung.
Cristik
7

Solusi saya yang sangat sederhana:

Swift 4.1:

let myString = "Test string"
let index = 0
let firstCharacter = myString[String.Index(encodedOffset: index)]

Swift 5.1:

let firstCharacter = myString[String.Index.init(utf16Offset: index, in: myString)]
Linh Dao
sumber
Bekerja di Swift 4.1
leanne
Solusi paling sederhana dan sekarang dengan contoh Swift 5 :)
OhadM
@Linh Dao Jangan gunakan encodedOffset. encodedOffset sudah tidak digunakan lagi: encodedOffset sudah tidak digunakan lagi karena sebagian besar penggunaannya salah.
Leo Dabus
@OhadM paling sederhana tidak berarti itu benar atau setidaknya itu tidak akan berfungsi seperti yang Anda harapkan Cobalet flags = "πŸ‡ΊπŸ‡ΈπŸ‡§πŸ‡·" flags[String.Index(utf16Offset: 4, in: flags)] // "πŸ‡§πŸ‡·"
Leo Dabus
1
@ Oh, komentar saya hanya peringatan. Jatuh bebas untuk menggunakannya jika Anda berpikir bahwa itu berperilaku seperti yang Anda harapkan.
Leo Dabus
6

Anda dapat melakukannya dengan mengonversi String ke Array dan mendapatkannya dengan indeks spesifik menggunakan subskrip seperti di bawah ini

var str = "Hello"
let s = Array(str)[2]
print(s)
Soeng Saravit
sumber
1
Perhatikan bahwa solusi ini akan menghasilkan duplikasi konten, membuatnya kurang berkinerja memori dan CPU-bijaksana.
Cristik
5

Saya baru saja mengalami masalah yang sama. Cukup lakukan ini:

var aString: String = "test"
var aChar:unichar = (aString as NSString).characterAtIndex(0)
pengguna3723247
sumber
Ini gagal untuk banyak Emoji dan karakter lain yang sebenarnya mengambil lebih dari satu kali "karakter" dalam sebuah NSString.
rmaddy
5

Swift3

Anda dapat menggunakan sintaksis subskrip untuk mengakses Karakter pada indeks String tertentu.

let greeting = "Guten Tag!"
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index] // a

Mengunjungi https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html

atau kita bisa melakukan String Extension di Swift 4

extension String {
    func getCharAtIndex(_ index: Int) -> Character {
        return self[self.index(self.startIndex, offsetBy: index)]
    }
}

PEMAKAIAN:

let foo = "ABC123"
foo.getCharAtIndex(2) //C
Hamed
sumber
3

Solusi saya ada dalam satu baris, seandainya cadena adalah string dan 4 adalah posisi ke-9 yang Anda inginkan:

let character = cadena[advance(cadena.startIndex, 4)]

Sederhana ... Saya kira Swift akan memasukkan lebih banyak hal tentang substring di versi mendatang.

Julio CΓ©sar FernΓ‘ndez MuΓ±oz
sumber
1
Bukankah itu sama dengan var charAtIndex = string[advance(string.startIndex, 10)]jawaban Sulthan?
Martin R
Ya, itu solusi yang sama dengan contoh lain seperti yang dikatakan Sulthan. Maaf untuk duplikat. :) Sangat mudah dua orang menemukan cara yang sama.
Julio CΓ©sar FernΓ‘ndez MuΓ±oz
3

Swift 3: solusi lain (diuji di taman bermain)

extension String {
    func substr(_ start:Int, length:Int=0) -> String? {
        guard start > -1 else {
            return nil
        }

        let count = self.characters.count - 1

        guard start <= count else {
            return nil
        }

        let startOffset = max(0, start)
        let endOffset = length > 0 ? min(count, startOffset + length - 1) : count

        return self[self.index(self.startIndex, offsetBy: startOffset)...self.index(self.startIndex, offsetBy: endOffset)]
    }
}

Pemakaian:

let txt = "12345"

txt.substr(-1) //nil
txt.substr(0) //"12345"
txt.substr(0, length: 0) //"12345"
txt.substr(1) //"2345"
txt.substr(2) //"345"
txt.substr(3) //"45"
txt.substr(4) //"5"
txt.substr(6) //nil
txt.substr(0, length: 1) //"1"
txt.substr(1, length: 1) //"2"
txt.substr(2, length: 1) //"3"
txt.substr(3, length: 1) //"4"
txt.substr(3, length: 2) //"45"
txt.substr(3, length: 3) //"45"
txt.substr(4, length: 1) //"5"
txt.substr(4, length: 2) //"5"
txt.substr(5, length: 1) //nil
txt.substr(5, length: -1) //nil
txt.substr(-1, length: -1) //nil
Peter Kreinz
sumber
2

Perbarui untuk subString cepat 2.0

public extension String {
    public subscript (i: Int) -> String {
        return self.substringWithRange(self.startIndex..<self.startIndex.advancedBy(i + 1))
    }

    public subscript (r: Range<Int>) -> String {
        get {
            return self.substringWithRange(self.startIndex.advancedBy(r.startIndex)..<self.startIndex.advancedBy(r.endIndex))
        }
    }

}
YannSteph
sumber
2

Saya pikir jawaban cepat untuk mendapatkan karakter pertama adalah:

let firstCharacter = aString[aString.startIndex]

Ini jauh lebih elegan dan kinerja daripada:

let firstCharacter = Array(aString.characters).first

Tapi .. jika Anda ingin memanipulasi dan melakukan lebih banyak operasi dengan string, Anda dapat berpikir membuat ekstensi .. ada satu ekstensi dengan pendekatan ini, itu sangat mirip dengan yang sudah diposting di sini:

extension String {
var length : Int {
    return self.characters.count
}

subscript(integerIndex: Int) -> Character {
    let index = startIndex.advancedBy(integerIndex)
    return self[index]
}

subscript(integerRange: Range<Int>) -> String {
    let start = startIndex.advancedBy(integerRange.startIndex)
    let end = startIndex.advancedBy(integerRange.endIndex)
    let range = start..<end
    return self[range]
}

}

TAPI ITU GAGASAN YANG MENGERIKAN !!

Ekstensi di bawah ini sangat tidak efisien. Setiap kali string diakses dengan integer, fungsi O (n) untuk memajukan indeks awal dijalankan. Menjalankan loop linier di dalam loop linier lain berarti ini untuk loop secara tidak sengaja O (n2) - karena panjang string meningkat, waktu yang dibutuhkan loop ini meningkat secara kuadratik.

Alih-alih melakukan itu Anda bisa menggunakan koleksi string karakter.

ignaciohugog
sumber
2

Cepat 3

extension String {

    public func charAt(_ i: Int) -> Character {
        return self[self.characters.index(self.startIndex, offsetBy: i)]
    }

    public subscript (i: Int) -> String {
        return String(self.charAt(i) as Character)
    }

    public subscript (r: Range<Int>) -> String {
        return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound)..<self.characters.index(self.startIndex, offsetBy: r.upperBound))
    }

    public subscript (r: CountableClosedRange<Int>) -> String {
        return substring(with: self.characters.index(self.startIndex, offsetBy: r.lowerBound)..<self.characters.index(self.startIndex, offsetBy: r.upperBound))
    }

}

Pemakaian

let str = "Hello World"
let sub = str[0...4]

Tips dan Trik Pemrograman yang Membantu (ditulis oleh saya)

unik
sumber
2

Dapatkan & Atur Langganan (String & Substring) - Swift 4.2

Swift 4.2, Xcode 10

Saya mendasarkan jawaban saya dari jawaban @alecarlson . Satu-satunya perbedaan besar adalah Anda bisa mendapatkan Substringatau Stringmengembalikan (dan dalam beberapa kasus, satu Character). Anda juga bisa getdan setsubskrip. Terakhir, milik saya sedikit lebih rumit dan lebih panjang dari jawaban @alecarlson dan karena itu, saya sarankan Anda memasukkannya ke file sumber.


Perpanjangan:

public extension String {
    public subscript (i: Int) -> Character {
        get {
            return self[index(startIndex, offsetBy: i)]
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ..< end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ... end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ..< end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> String {
        get {
            return "\(self[index(startIndex, offsetBy: i)])"
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            self.replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ..< end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ... end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ..< end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> Substring {
        get {
            return Substring("\(self[index(startIndex, offsetBy: i)])")
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
}
public extension Substring {
    public subscript (i: Int) -> Character {
        get {
            return self[index(startIndex, offsetBy: i)]
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }

    }
    public subscript (bounds: CountableRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ..< end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> Substring {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return self[start ... end]
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: PartialRangeThrough<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ... end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> Substring {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return self[startIndex ..< end]
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }
    public subscript (i: Int) -> String {
        get {
            return "\(self[index(startIndex, offsetBy: i)])"
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
    public subscript (bounds: CountableRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ..< end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ..< end, with: s)
        }
    }
    public subscript (bounds: CountableClosedRange<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(start ... end, with: s)
        }

    }
    public subscript (bounds: CountablePartialRangeFrom<Int>) -> String {
        get {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            return "\(self[start ... end])"
        }
        set (s) {
            let start = index(startIndex, offsetBy: bounds.lowerBound)
            let end = index(endIndex, offsetBy: -1)
            replaceSubrange(start ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeThrough<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ... end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ... end, with: s)
        }
    }
    public subscript (bounds: PartialRangeUpTo<Int>) -> String {
        get {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            return "\(self[startIndex ..< end])"
        }
        set (s) {
            let end = index(startIndex, offsetBy: bounds.upperBound)
            replaceSubrange(startIndex ..< end, with: s)
        }
    }

    public subscript (i: Int) -> Substring {
        get {
            return Substring("\(self[index(startIndex, offsetBy: i)])")
        }
        set (c) {
            let n = index(startIndex, offsetBy: i)
            replaceSubrange(n...n, with: "\(c)")
        }
    }
}
Noah Wilder
sumber
Ini tidak perlu mengimbangi kedua indeks (mulai dan akhir) dari startIndex. Anda cukup mengimbangi indeks akhir menggunakan range.count dan mengimbangi indeks awal
Leo Dabus
2

Cepat 4.2

Jawaban ini sangat ideal karena meluas Stringdan semua Subsequences( Substring) dalam satu ekstensi

public extension StringProtocol {

    public subscript (i: Int) -> Element {
        return self[index(startIndex, offsetBy: i)]
    }

    public subscript (bounds: CountableClosedRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[start...end]
    }

    public subscript (bounds: CountableRange<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[start..<end]
    }

    public subscript (bounds: PartialRangeUpTo<Int>) -> SubSequence {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[startIndex..<end]
    }

    public subscript (bounds: PartialRangeThrough<Int>) -> SubSequence {
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return self[startIndex...end]
    }

    public subscript (bounds: CountablePartialRangeFrom<Int>) -> SubSequence {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        return self[start..<endIndex]
    }
}

Pemakaian

var str = "Hello, playground"

print(str[5...][...5][0])
// Prints ","
Noah Wilder
sumber
Ini tidak perlu mengimbangi kedua indeks ( startdan end) dari startIndex. Anda cukup mengimbangi endindeks menggunakan range.count dan mengimbangi startindeks
Leo Dabus
2

Sekarang, subskrip (_ :) tidak tersedia. Kita juga tidak bisa melakukan ini

str[0] 

dengan string. Kita harus menyediakan "String.Index" Tapi, bagaimana kita bisa memberikan nomor indeks kita sendiri dengan cara ini, sebagai gantinya kita bisa menggunakan,

string[str.index(str.startIndex, offsetBy: 0)]
Yodagama
sumber
Harap edit jawaban Anda dan tambahkan beberapa konteks dengan menjelaskan bagaimana jawaban Anda memecahkan masalah, alih-alih memposting jawaban hanya kode. Dari Ulasan
Pedram Parsian
Mengapa melakukan penyeimbangan yang tidak perlu? Kenapa tidak sederhana saja string[string.startIndex]? BTW, kode tidak akan berperilaku / kompilasi dengan benar, karena Anda menggunakan dua nama variabel yang berbeda.
Cristik
2

Swift 4.2 atau lebih baru

Range dan subscripting berbagai parsial menggunakan String'sindices properti

Sebagai variasi dari jawaban bagus @LeoDabus , kami dapat menambahkan ekstensi tambahan DefaultIndicesdengan tujuan memungkinkan kami untuk kembali ke indicesproperti Stringketika menerapkan subskrip khusus (dengan Intrentang khusus dan rentang parsial) untuk yang terakhir.

extension DefaultIndices {
    subscript(at: Int) -> Elements.Index { index(startIndex, offsetBy: at) }
}

// Moving the index(_:offsetBy:) to an extension yields slightly
// briefer implementations for these String extensions.
extension String {
    subscript(range: Range<Int>) -> SubSequence {
        let start = indices[range.lowerBound]
        return self[start..<indices[start...][range.count]]
    }
    subscript(range: ClosedRange<Int>) -> SubSequence {
        let start = indices[range.lowerBound]
        return self[start...indices[start...][range.count]]
    }
    subscript(range: PartialRangeFrom<Int>) -> SubSequence {
        self[indices[range.lowerBound]...]
    }
    subscript(range: PartialRangeThrough<Int>) -> SubSequence {
        self[...indices[range.upperBound]]
    }
    subscript(range: PartialRangeUpTo<Int>) -> SubSequence {
        self[..<indices[range.upperBound]]
    }
}

let str = "foo bar baz bax"
print(str[4..<6]) // "ba"
print(str[4...6]) // "bar"
print(str[4...])  // "bar baz bax"
print(str[...6])  // "foo bar"
print(str[..<6])  // "foo ba"

Terima kasih @LeoDabus karena menunjukkan saya ke arah penggunaan indicesproperti sebagai alternatif (lain) untuk Stringberlangganan!

dfri
sumber
1
satu-satunya kelemahan adalah CountableClosedRange akan mengimbangi kedua indeks dari startIndex
Leo Dabus
1
@LeoDabus, begitu. Ya sebagian besar linux tetapi tidak banyak Swift hari ini: / Saya menggunakan swiftenvketika saya lakukan, saya kira itu akan diperbarui dengan 4.2 juga agak segera.
dfri
1
@LeoDabus terima kasih telah memperbarui jawaban ini ke Swift modern!
dfri
1
@LeoDabus kerja bagus! Harus melihat detail di lain waktu, tetapi saya ingat bahwa saya tidak pernah suka bahwa kami harus kembali ke Foundation beberapa jenis set yang dipesan / dapat dihitung.
dfri
1
terimakasih kawan!!!
Leo Dabus
2

Swift 5.1.3:

Tambahkan ekstensi String:

extension String {

 func stringAt(_ i: Int) -> String { 
   return String(Array(self)[i]) 
 } 

 func charAt(_ i: Int) -> Character { 
  return Array(self)[i] 
 } 
}

let str = "Teja Kumar"
let str1: String = str.stringAt(2)  //"j"
let str2: Character = str.charAt(5)  //"k"
Teja Kumar Bethina
sumber
1
Ini akan mengonversi seluruh string menjadi array karakter setiap kali Anda memanggil properti ini untuk mengekstrak satu karakter darinya.
Leo Dabus
1

StringJenis Swift tidak menyediakan characterAtIndexmetode karena ada beberapa cara string Unicode dapat dikodekan. Apakah Anda menggunakan UTF8, UTF16, atau yang lainnya?

Anda dapat mengakses CodeUnitkoleksi dengan mengambil String.utf8dan String.utf16properti. Anda juga dapat mengakses UnicodeScalarkoleksi dengan mengambil String.unicodeScalarsproperti.

Dalam semangat NSStringimplementasi, saya mengembalikan sebuah unichartipe.

extension String
{
    func characterAtIndex(index:Int) -> unichar
    {
        return self.utf16[index]
    }

    // Allows us to use String[index] notation
    subscript(index:Int) -> unichar
    {
        return characterAtIndex(index)
    }
}

let text = "Hello Swift!"
let firstChar = text[0]
Erik
sumber
Ini akan gagal untuk karakter yang membutuhkan penyimpanan lebih dari 16 bit. Pada dasarnya, setiap karakter Unicode di luar U + FFFF.
rmaddy
1

Untuk memberi makan subjek dan menunjukkan kemungkinan subskrip cepat, berikut ini adalah string subskrip "substring-toolbox"

Metode ini aman dan tidak pernah melewati indeks string

extension String {
    // string[i] -> one string char
    subscript(pos: Int) -> String { return String(Array(self)[min(self.length-1,max(0,pos))]) }

    // string[pos,len] -> substring from pos for len chars on the left
    subscript(pos: Int, len: Int) -> String { return self[pos, len, .pos_len, .left2right] }

    // string[pos, len, .right2left] -> substring from pos for len chars on the right
    subscript(pos: Int, len: Int, way: Way) -> String { return self[pos, len, .pos_len, way] }

    // string[range] -> substring form start pos on the left to end pos on the right
    subscript(range: Range<Int>) -> String { return self[range.startIndex, range.endIndex, .start_end, .left2right] }

    // string[range, .right2left] -> substring start pos on the right to end pos on the left
    subscript(range: Range<Int>, way: Way) -> String { return self[range.startIndex, range.endIndex, .start_end, way] }

    var length: Int { return countElements(self) }
    enum Mode { case pos_len, start_end }
    enum Way { case left2right, right2left }
    subscript(var val1: Int, var val2: Int, mode: Mode, way: Way) -> String {
        if mode == .start_end {
            if val1 > val2 { let val=val1 ; val1=val2 ; val2=val }
            val2 = val2-val1
        }
        if way == .left2right {
            val1 = min(self.length-1, max(0,val1))
            val2 = min(self.length-val1, max(1,val2))
        } else {
            let val1_ = val1
            val1 = min(self.length-1, max(0, self.length-val1_-val2 ))
            val2 = max(1, (self.length-1-val1_)-(val1-1) )
        }
        return self.bridgeToObjectiveC().substringWithRange(NSMakeRange(val1, val2))

        //-- Alternative code without bridge --
        //var range: Range<Int> = pos...(pos+len-1)
        //var start = advance(startIndex, range.startIndex)
        //var end = advance(startIndex, range.endIndex)
        //return self.substringWithRange(Range(start: start, end: end))
    }
}


println("0123456789"[3]) // return "3"

println("0123456789"[3,2]) // return "34"

println("0123456789"[3,2,.right2left]) // return "56"

println("0123456789"[5,10,.pos_len,.left2right]) // return "56789"

println("0123456789"[8,120,.pos_len,.right2left]) // return "01"

println("0123456789"[120,120,.pos_len,.left2right]) // return "9"

println("0123456789"[0...4]) // return "01234"

println("0123456789"[0..4]) // return "0123"

println("0123456789"[0...4,.right2left]) // return "56789"

println("0123456789"[4...0,.right2left]) // return "678" << because ??? range can wear endIndex at 0 ???
Luc-Olivier
sumber
1

Solusi mirip python, yang memungkinkan Anda menggunakan indeks negatif,

var str = "Hello world!"
str[-1]        // "!"

bisa jadi:

extension String {
    subscript (var index:Int)->Character{
        get {
            let n = distance(self.startIndex, self.endIndex)
            index %= n
            if index < 0 { index += n }
            return self[advance(startIndex, index)]
        }
    }
}

Ngomong-ngomong, mungkin layak untuk mengubah notasi irisan seluruh python

Joseph Merdrignac
sumber
Apakah Anda keberatan menulis sesuatu yang dapat dikompilasi untuk Swift 4? terakhir kembali ... baris sepertinya tidak berfungsi muka () fungsi tidak ada saya percaya.
C0D3
1

Anda juga dapat mengonversi String ke Array of Characters seperti itu:

let text = "My Text"
let index = 2
let charSequence = text.unicodeScalars.map{ Character($0) }
let char = charSequence[index]

Ini adalah cara untuk mendapatkan char pada indeks yang ditentukan dalam waktu yang konstan.

Contoh di bawah ini tidak berjalan dalam waktu konstan, tetapi membutuhkan waktu linier. Jadi, jika Anda memiliki banyak pencarian di String oleh indeks, gunakan metode di atas.

let char = text[text.startIndex.advancedBy(index)]
Marcin Kapusta
sumber