String.substringWithRange nasıl kullanılır? (veya Ranges Swift'te nasıl çalışır?)


266

StringSwift'te bir alt dizeyi nasıl alacağımı henüz anlayamadım :

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

Swift'te bir Range oluşturamıyorum. Oyun alanındaki otomatik tamamlama süper yararlı değildir - bu önerdiği şeydir:

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

Swift Standart Referans Kütüphanesinde yardımcı olacak hiçbir şey bulamadım. İşte başka bir vahşi tahmin:

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

Ve bu:

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

Ben bir köprü türü olduğu için , "eski" yöntemleri çalışması gerektiğini, ancak nasıl açık değil - örneğin, bu da işe yaramıyor gibi görünüyor başka cevaplar ( Swift String karakter dizini bulma) gördüm geçerli bir sözdizimi gibi görünmüyor):StringNSString

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

Düşünceler?


Son örneğin işe yaramadığını söylediğinde ne demek istiyorsun? Bir hataya neden oluyor veya beklenmeyen bir değer döndürüyor mu?
67cherries

Lütfen dupe rdar: // 17158813 alt simge notasyonu isteğinde bulunun openradar.appspot.com/radar?id=6373877630369792
Rob Napier

Yanıtlar:


259

SubstringWithRange yöntemini kullanabilirsiniz. Bir başlangıç ​​ve bitiş String.Index alır.

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

Başlangıç ​​ve bitiş dizinini değiştirmek için advancedBy (n) kullanın.

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

Yine de NSRange ile NSString yöntemini kullanabilirsiniz, ancak aşağıdaki gibi bir NSString kullandığınızdan emin olmalısınız:

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

Not: JanX2'nin belirttiği gibi, bu ikinci yöntem unicode dizelerle güvenli değildir.


5
Evet. Şimdilik gerektiğinde NSString'e köprülemeye devam edecektim. Swift'in String'i hala eksik görünüyor
Connor

14
Bu güvenli değil! String ve NSString dizinlerinin değiştirilebilir olduğunu varsayıyorsunuz. Durum böyle değil. Bir Dize içindeki dizinler Unicode kod noktalarını, NSString dizinleri ise UTF-16 kod birimlerini ifade eder! Emoji ile deneyin.
JanX2

3
Bir Dize İçindeki Dizinlerin artık Unicode kod noktalarına başvurmadığını lütfen unutmayın. Bunları, kullanıcı tarafından algılanan karakterlere gönderme olarak düşünün.
JanX2

2
Peki burada doğru cevap nedir? Arama advancedemek, uzun bir ip üzerinden tüm yolu tekrarlamak zorunda olduğumuz anlamına gelir. Ancak bir NSRange oluşturmak ve NSString'i açıkça kullanmak tehlikelidir? Ne kaldı?
mat

1
Teşekkürler, m8. Swift'e geçiş 4 yıl sonra sadece Objective-C yaptıktan sonra biraz dağınık.
Felipe

162

Hızlı 2

Basit

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

Hızlı 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"

Hızlı 4

substring(to:)ve substring(from:)kullanımdan kaldırıldı Swift 4.

String(str[..<startIndex])    // "My "
String(str[startIndex...])    // "String"
String(str[startIndex...endIndex])    // "Strin"

2
BU. O kadar kafa karıştırıcı ki kullanmadan önce dizininizi bulmalısınız. Fark etmem neden bu kadar uzun sürdü bilmiyorum ama insan türüne katkınız için teşekkür ederim.
Warpzit

1
Hızlı 4 alt dize işlemlerinde, Dize yerine Alt Dize türünün bir örneğini döndürün. Uzun süreli depolama için sonucu bir String'e dönüştürmeniz gerekir. let newString = Dize (alt dize)
phnmnn

43

NOT: @airspeedswift bazı yapar çok anlayışlı noktaları bu yaklaşım, özellikle gizli performans etkilerin dengeler üzerinde. Dizeler basit canavarlar değildir ve belirli bir dizine ulaşmak O (n) zaman alabilir, yani bir alt simge kullanan bir döngü O (n ^ 2) olabilir. Uyarıldın.

Sadece subscriptbir dizi alan ve advancedBy()istediğiniz yere yürümek için kullanılan yeni bir işlev eklemeniz gerekir :

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"

(Bu kesinlikle dilin bir parçası olmalıdır. Lütfen dupe rdar: // 17158813 )

Eğlenmek +için dizinlere bir operatör de ekleyebilirsiniz :

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)

(Bunun dilin bir parçası olup olmayacağını henüz bilmiyorum.)


2
Muhtemelen performans nedenleriyle tamsayı dizinleri yerine String.Index ile çalışmalıyız. Bir tamsayı dizininden bir String.Index dosyasına yapılan her dönüştürmenin, arama yapmak için dizeyi işlemesi gerekir.
JanX2

11
@AndrewDunn Bu, erken optimizasyon değildir. Bir tamsayı dizininden bir String.Index dosyasına yapılan her dönüştürme O (1) değil, O (n) 'dir! İçin bir yorum okuyunuz advance<T>(…)içinde Swiftad.
JanX2

1
Dize uygulamasının tamamı kullanılarak yapılır String.Index. Bu durumda, her şeyi basit tuttuğu kadar optimizasyon değildir. İnt ve String.Index arasında her yerde ileri geri gitmek zorunda olmak bir karmaşaya yol açacaktır.
chakrit

@chakrit Yalnızca kullanmanız gereken dizinler String.Indexgenellikle tamsayı değilse ( es yerine ) tamsayı değildir . Daha sen sadece tüm bu dize işleme yöntemleri Ints ile çalışmak isteyebilirsiniz . Ve bunu String.Indexesbahsettiğiniz karmaşaya dönüştürmek zorundasınız.
Rasto

İlgilenen okuyucu ExSwift'e bir göz atmalıdır github.com/pNre/ExSwift
AsTeR

42

Ben yazarken, hiçbir uzantı mükemmel Swift 4.2 uyumlu değildir, bu yüzden aklıma gelen tüm ihtiyaçları kapsayan bir tane:

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)
    }
}

Ve sonra şunları kullanabilirsiniz:

let string = "Hello,World!"

string.substring(from: 1, to: 7)seni alır: ello,Wo

string.substring(to: 7)seni alır: Hello,Wo

string.substring(from: 3)seni alır: lo,World!

string.substring(from: 1, length: 4)seni alır: ello

string.substring(length: 4, to: 7)seni alır: o,Wo

substring(from: Int?, length: Int)Sıfırdan başlayarak desteklenecek şekilde güncellendi .


Bu emoji ve genişletilmiş grafik kümelerini nasıl ele alır? (Kendim test etmeliyim ama şu anda uygun değil.)
16:16 tarihinde Suragch

2
Tamam bunu kolları @Suragch: "Hello😇😍😘😎📸📀💾∝ℵℶ≹".substring(from: 4, to: 14)Bize verir:o😇😍😘😎📸📀💾∝ℵℶ
winterized

Bunlar normal karakterlere benziyor. 👩‍👩‍👧‍👦 veya 🇨🇦🇺🇸🇲🇽
Supuhstar

31

SWIFT 2.0

basit:

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

Alt dize işlemleri, Dize yerine Alt Dize türünün bir örneğini döndürür.

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)

4
Ne yazık ki Xcode 8 beta 6'dan itibaren Swift 3 ile uyumlu değil
Ben Morrow

1
Benim için çalışıyor. Xcode 8, Swift 3. Mac OS Sierra'da beta değil. text[text.startIndex..<text.index(text.startIndex, offsetBy: 2)]
Jose Ramirez

18

Doğru sözdizimini bulduğunuzda, buradaki yanıtlardan herhangi birinden çok daha basittir.

[Ve]

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 )

sonuç "ABCDEFGHI" olacaktır startIndex ve endIndex de kullanılabilir

let mySubString = myString.substringFromIndex(startIndex)

ve bunun gibi!

Not: Açıklamalarda belirtildiği gibi, hızlı 2'de xcode 7 ve iOS9 ile gelen bazı sözdizimi değişiklikleri var!

Lütfen bu sayfaya bakın


Evet, hata ayıklayıcı ile doğru dize birkaç kez göstermiyorum aynı sorunları vardı?
user1700737

böyle bir dize var / Tarih (147410000000) /. Dizini belirtmek yerine değeri nasıl alabilirim. RangeOfString ("(") ve rangeOfString (")") kullanarak değeri almanız gerekir. Sonuç 147410000000 olmalıdır. Çapa alabilirim
iPhone Guy

Çok zor değil: var str = "/ Tarih (147410000000) /." var range = str.rangeOfString ("(") !. endIndex .. <str.rangeOfString (")") !. startIndex, myNewString = str.substringWithRange (aralık)
user1700737 29:14

4
Xcode 7 beta 6 advance(myString.endIndex, -1)sözdizimimyString.endIndex.advancedBy(-1)
l --marc l olarak

16

Örneğin, tam adımdaki ilk adı (ilk boşluğa kadar) bulmak için:

let name = "Joris Kluivers"

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

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

startve endtiptedir String.Indexburada ve bir oluşturmak için kullanılır Range<String.Index>(bir boşluk orijinal dizede hiç bulunursa) ve alt simge erişgeç kullanılan.

String.IndexAçılış direğinde kullanılan bir tamsayı konumundan doğrudan oluşturmak zordur . Çünkü benim adımda her karakter bayt cinsinden eşit boyutta olurdu. Ancak diğer dillerde özel aksanlar kullanan karakterler birkaç bayt daha kullanmış olabilir (kullanılan kodlamaya bağlı olarak). Peki tamsayı hangi bayttan bahsetmeli?

String.IndexYöntemleri kullanarak var olandan yeni bir tane oluşturmak mümkündür succve predbu da kodlamanın bir sonraki kod noktasına ulaşmak için doğru sayıda bayt atlandığından emin olur. Ancak bu durumda, son dizini bulmak için dizedeki ilk boşluğun dizinini aramak daha kolaydır.


16

Dize, NSString için bir köprü türü olduğundan, "eski" yöntemlerin çalışması gerekir, ancak bunun nasıl yapılacağı açık değildir - örneğin, bu da çalışmaz (geçerli sözdizimi gibi görünmüyor):

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

Bana göre, sorunuzun gerçekten ilginç kısmı bu. Dize edilir böylece, NSString köprülü en NSString yöntemleri yapmak bir dize doğrudan işi. Onları özgürce ve düşünmeden kullanabilirsiniz. Örneğin, bu beklediğiniz gibi çalışır:

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

Ancak, sık sık olduğu gibi, "Ben mojo çalışıyorum" ama sadece senin üzerinde çalışmıyor. " Aynı adı taşıyan bir Swift yönteminin bulunduğu nadir durumlardan birini seçtiniz ve böyle bir durumda Swift yöntemi Objective-C yöntemini gölgede bırakıyor. Bu nedenle, str.substringWithRangeSwift dediğinde , NSString yöntemi yerine Swift yöntemini kastettiğini düşünüyor - ve sonra hosed sen, çünkü Swift yöntemi a'yı bekliyor Range<String.Index>ve bunlardan birini nasıl yapacağını bilmiyorsun.

Kolay çıkış yolu, Swift'in açık bir şekilde yayınlayarak böyle gölgelenmesini önlemektir:

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

Burada önemli bir ekstra iş yapılmadığını unutmayın. "Cast", "convert" anlamına gelmez; Yaylı olan etkin bir şekilde bir NSString. Swift'e sadece bu kod satırı için bu değişkene nasıl bakacağımızı anlatıyoruz .

Bütün bunların gerçekten garip olan kısmı, tüm bu sorunlara neden olan Swift yönteminin belgelenmemiş olmasıdır. Nerede tanımlandığı hakkında hiçbir fikrim yok; NSString başlığında değil ve Swift başlığında da yok.


Ancak, bir hata bildirmenizi öneririm. Apple "balık tutmalı ya da yem kesmeli" - ya bize bir inşa etmek için bir yol verin Range<String.Index>ya da bu belgesiz yöntemi yolumuzdan çıkarın.
matt

Lanet olsun - bu kullanışlı. Belgelerin söylediklerine rağmen, bunu okuyana kadar neyin yanlış gittiğini anlamadım. Şimdi sıralandı :)
Jon M

13

Yeni Xcode 7.0'da

//: 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:

resim açıklamasını buraya girin


2
.advancedBy(0) startIndex için gerekli değildir.
Mat0

12

Kısa cevap şu ki Swift'te şu anda gerçekten zor. Benim önsezim, Apple'ın böyle şeyler için kolaylık yöntemleri üzerinde yapması gereken bir sürü iş var.

String.substringWithRange()bir Range<String.Index>parametre bekliyor ve söyleyebildiğim kadarıyla String.Indextür için bir jeneratör yöntemi yok . Sen alabilirsiniz String.Indexdeğerleri elde geri aString.startIndexve aString.endIndexve çağrı .succ()veya .pred()üzerlerinde, ama 's delilik olduğunu.

String sınıfında iyi eski Ints alan bir uzantıya ne dersiniz ?

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))   // 🐶

Güncelleme: Swift beta 4 aşağıdaki sorunları çözüyor!

[Beta 3 ve daha önceki sürümlerde] olduğu gibi, Swift yerel dize bile Unicode karakterleri işlemek için bazı sorunlar var. Yukarıdaki köpek simgesi işe yaradı, ancak aşağıdakiler işe yaramadı:

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

Çıktı:

1
:
1
️
⃣

1
Garip, çekirdek Swift sınıflarının çok fazla temel işlevi yok gibi görünüyor. Apple'ın basit görevleri yerine getirmek için sürekli olarak Foundation sınıflarına başvurmamızı istediğini düşünemiyorum.
bluedevil2k

1
Tamamen. Swift'in temelde karanlıkta geliştirildiğini ve herkesin "basit görevler" in farklı bir tanımına sahip olduğunu unutmayın - Bahse girerim bu konularda hızlı bir yineleme görüyoruz.
Nate Cook

@ JanX2 - Teşekkürler, tamamen haklısın. Kesintisiz köprüleme NSStringbeni sadece Swift-yerli Stringyöntemleri kullandığımı düşündürdü , çünkü hiç myString as NSStringçağrı kullanmıyordum .
Nate Cook

Swift-yerel dize işlemesinde bazı Unicode hataları da var: sonunda notuma bakın.
Nate Cook

@NateCook Lütfen bu sorun için bir radar gönderebilir misiniz?
JanX2

11

Bu uzantıları geliştirmek için kullanabilirsiniz substringWithRange

Hızlı 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)
    }
}

Hızlı 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)
    }
}

Kullanımı:

let str = "Hello, playground"

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

7

Swift 2.0'da alt dize almak için örnek kod

(i) Başlangıç ​​endeksinden gelen alt dize

Giriş:-

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

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

Çıktı:-

Swift is very powerful language!
Swift

(ii) Belirli bir dizinden alt dize

Giriş:-

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

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

Çıktı:-

Swift is very powerful language!
is

Umarım bu sana yardımcı olur!


7

Az kod ile kolay çözüm.

Neredeyse tüm diğer dillerdeki temel alt dizeyi içeren bir uzantı oluşturun:

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)
    }
}

Sadece şununla ara

someString.subString(start: 0, end: 6)

1
'End' parametresi aslında burada uzunluk anlamına gelir, bu yüzden yeniden adlandırılması gerektiğini düşünüyorum.
Jovan Jovanovski

Bence uzunluk kullanmak oldukça kafa karıştırıcı. Aslında, subString'in gerçek uzunluğu değil, subString'in olmasını istediğiniz yerin 'sonu'.
Oliver Dixon

6

Bu oyun alanımda çalışıyor :)

String(seq: Array(str)[2...4])

Aslında bu aramaktan daha etkilidiradvance
Erik Aigner

2
Benim Xcode 7 (Swift 2) oyun alanımda çalışmıyor, ama bu ... 'var str = "Merhaba, oyun alanı"' String (Array (str.characters) [7]) // "p" String (Array ( str.characters) [7 ... 10]) // "play" String (Dizi (str.characters) [7 .. <10]) // "pla"
Vince O'Sullivan

6

Xcode 7 için güncellendi. Dize uzantısı ekler:

kullanın:

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

Uygulama:

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)
        }
    }

}

4

bunu oyun alanında dene

var str:String = "Hello, playground"

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

size "ello, p" verecek

Ancak bunun gerçekten ilginç hale geldiği nokta, son dizini oyun alanındaki dizeden daha büyük yaparsanız, str: o'dan sonra tanımladığınız tüm dizeleri göstermesidir.

Range () genel bir işlev gibi gözüküyor, böylece uğraştığı türü bilmesi gerekiyor.

Ayrıca, oyun alanlarıyla ilgilendiğiniz gerçek dizeyi, daha sonra değişken adlarıyla birbiri ardına bir sırayla tuttuğu gibi vermelisiniz.

Yani

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))

verir "ello, playground str'Bir sonraki dize str2 "

str2 bir let ile tanımlanmış olsa bile çalışır

:)


Ben Objective-C ile karşılaştırıldığında ayrıntılı olduğunu kabul ediyorum, ancak hepsi bir bonus olan bir satıra uyuyor.
Peter Roberts

Aslında, hesapladığınız aralık göz önüne alındığında alt dizeyi gerçekten basan bir satır eksik. Mantıkınızı kullanarak bir uzantıda String sınıfı uzantıları oluşturan diğer çözümlerden bazılarını seviyorum. Nihayetinde gittiğim çözüm buydu.
Roderic Campbell

Dizenin sonunun ötesine geçebileceğiniz hatayı düzelttiler. Şimdi sadece str.endIndex'e kadar bir değer koyabilirsiniz
Peter Roberts

4

Rob Napier zaten alt simge kullanarak harika bir cevap vermişti. Ama ben dışarıda koşulların kontrol için bir dezavantajı olduğunu hissettim. Bu çökme eğilimi gösterebilir. Bu yüzden uzantıyı değiştirdim ve işte burada

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)]
        }
    }
}

Çıktı aşağıda

var str2 = "Hello, World"

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

Bu yüzden her zaman eğer izin için kontrol etmenizi öneririz

if let string = str[0...5]
{
    //Manipulate your string safely
}

Orada bir hata var - endIndex startIndex sadece endIndex tarafından gelişmiş, endeksler arasındaki mesafe değil.
Aviad Ben Dov

3

In swift3

Örneğin: bir değişken "Duke James Thomas", "James" i almamız gerekiyor.

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)

2

Rob Napier'den bir sayfa alarak, bu Ortak Dize Uzantılarını geliştirdim , ikisi:

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))
}

Kullanımı:

"Awesome"[3...7] //"some"
"Awesome".subString(3, length: 4) //"some"

Tür çıkarımı Rangeyerine kullanabilirsiniz Range<String.Index>.
Dan Rosenstark

2

Bir dizeden bir aralığı şu şekilde elde edersiniz:

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"

Anahtar nokta, tamsayılar yerine String.Index türünde bir dizi değer geçirmenizdir (bu, ilerlemenin geri dönüşüdür).

Bunun gerekli olmasının nedeni, Swift'teki dizelerin rastgele erişime sahip olmamasıdır (temelde Unicode karakterlerin değişken uzunluğu nedeniyle). Sen de yapamazsın str[1]. String.Index iç yapılarıyla çalışacak şekilde tasarlanmıştır.

Bununla birlikte, bunu sizin için yapan bir aboneliğe sahip bir uzantı oluşturabilirsiniz, böylece bir dizi tam sayı iletebilirsiniz (bkz. Örneğin Rob Napier'in cevabı ).


2

Pythonic bir şey bulmaya çalıştım.

Buradaki tüm abonelikler harika, ama gerçekten basit bir şeye ihtiyacım olan zamanlar genellikle arkadan saymak istediğim zamandır, örn. string.endIndex.advancedBy(-1)

nilHem başlangıç ​​hem de bitiş dizini için değerleri destekler ; burada nilbaşlangıç string.characters.countiçin bitiş için 0'da dizin anlamına gelir .

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!!

DÜZENLE

Daha zarif bir çözüm:

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!!

1

Önce aralığı, ardından alt dizeyi oluşturun. fromIndex..<toIndexSözdizimini şu şekilde kullanabilirsiniz :

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

1

İşte tüm URL'den hızlı bir şekilde yalnızca video kimliği almak için bir örnek .ie (6oL687G0Iso)

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)

1
let startIndex = text.startIndex
var range = startIndex.advancedBy(1) ..< text.endIndex.advancedBy(-4)
let substring = text.substringWithRange(range)

Tam örnek burada görebilirsiniz



0

Ben de aynı sorunu vardı ve "bridgeToObjectiveC ()" fonksiyonu ile çözüldü:

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

Örnekte, NSMakeRange ile birlikte subringWithRange'ın dizenin dizin 6'dan başlayarak ("W" karakteri) ve dizin 6 + 6 konumlarında bitmeden (karakter "!") Biteceğini unutmayın.

Şerefe.


Bundan nefret ediyorum, ancak Beta 4'te benim için çalışıyor gibi görünen tek şey.
Roderic Campbell

0

Https://bit.ly/JString yazdığım Swift String uzantısında alt dize yöntemlerinden herhangi birini kullanabilirsiniz .

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

0

Eğer varsa NSRange, köprüleme NSStringsorunsuz çalışır. Örneğin, bazı işler yapıyordum UITextFieldDelegateve aralığın yerine geçip geçmeyeceğini sorduğunda yeni dize değerini hızlıca hesaplamak istedim.

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)
}

0

Aşağıdakiler için basit uzantıString :

extension String {

    func substringToIndex(index: Int) -> String {
        return self[startIndex...startIndex.advancedBy(min(index, characters.count - 1))]
    }
}

0

Performansı önemsemiyorsanız ... bu muhtemelen Swift 4'teki en özlü çözümdür

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

Bunun gibi bir şey yapmanızı sağlar:

let myStr = "abcd"
myStr[0..<2] // produces "ab"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.