how to get subString from String

Hi,

how to get a substring (a range of characters) from a String?

  1. let str = "abcdefghi"
  2. // Say I'd like to get the substring str.characters[3 ..< 6], ie "def".
  3. let substr = ???
  4. print(substr) // "def"

I see the link of https://forums.developer.apple.com/message/49875#49875

for example:

let substr = str[str.startIndex.advancedBy(3)..<str.startIndex.advancedBy(6)]

Or this may be a little more efficient:

  1. let s = str.startIndex.advancedBy(3)
  2. let e = s.advancedBy(3)
  3. let substr = str[s..<e]


but I do not understand the meaning,what's the "advacedBy",is not exist of th swift synatx?

Please help me !


Thanks,

luo

One reason is the complexity issue written in the thread you referred.

Another reason is to hide the implementation details.

You may have read this article: Strings in Swift 2


Assume the string is as follows:


var str = "a\u{e9}\u{3042}\u{1f436}\u{1f1fa}\u{1f1f8}f"

(It seems the editor of the forums does not like emoji characters. See what's contained in `str` in the Playground.)


The string above contains 6 characters, but its internal representation may be something like this:

in utf16 index
[0]  [1]  [2]  [3]  [4]  [5]  [6]  [7]  [8]  [9]  [10]
0061 00e9 3042 d83d dc36 d83c ddfa d83c ddf8 0066 (end)
[0]  [1]  [2]  [3]-----> [4]---------------> [5]  [6]
in characters

If you want to get a substring with character range 3..<6, you need to collect utf16 code units 3..<10 .

let s = str.startIndex.advancedBy(3) calculates the internal utf16 index[3] by characters count

let s = s.advancedBy(3) calculates the internal utf16 index[10] (end of string) by characters count


The `str` may have other representation like utf8 or unicodeScalar, but using advancedBy, you need not to know the implementation details, and you can get the right position hidden inside String.Index.


But, knowing such things, I sometimes get really annoyed writing String handling codes in Swift.

I believe Swift team could provide many more convenience methods, without breaking the features like described above.


ADDITION:

You've already found some extensions for Swift String in that thread. Here is another:

extension String {
    func indexByInt(index: Int) -> Index {
        if index >= 0 {
            return self.startIndex.advancedBy(index)
        } else {
            return self.endIndex.advancedBy(index)
        }
    }
    func substringByInt(start: Int, _ end: Int? = nil) -> String {
        let startIndex = self.indexByInt(start)
        let endIndex = end != nil ? self.indexByInt(end!) : self.endIndex
        if startIndex <= endIndex {
            return self.substringWithRange(startIndex..<endIndex)
        } else {
            return ""
        }
    }
    func substringByInt(range: Range<Int>) -> String {
        return self.substringByInt(range.startIndex, range.endIndex)
    }
}
str.substringByInt(2)
str.substringByInt(0, 4)
str.substringByInt(0, -2)
str.substringByInt(3..<6)

This example is not super-efficient. You can improve it, once you understand the basics of Swift String.

Thans for your reply!

but I get error "String.index does nor have a member named advancedBy" when I write the code of " let s = str.startIndex.advancedBy(3)"

Xcode version 6.4.3

Accepted Answer

In Swift 1.2 (in Xcode 6.4) there was no advancedBy method, but advance function.

Code using adavancedBy method in Swift 2 like:

let s = str.startIndex.advancedBy(3)

needed to be written as follows in Swift 1.2:

let s = advance(str.startIndex, 3)


Some other points about String have changed from Swift 1.2 to Swift 2, but my extension example should work if you fix two lines using advancedBy.


By the way, Xcode 7 supports all Macs which can run Xcode 6.4. Get a chance to make your Xcode upgraded and try Swift 2.

It's very kind of you that I know the reason of the error.


however , how to get the change of swift 1.2 and swift 2.0 ?

Could you provide some links or webs ?



Thanks,

luo

however , how to get the change of swift 1.2 and swift 2.0 ?

Could you provide some links or webs ?


It was a huge change, from Swift 1.2 to Swift 2. Also iOS SDK/OS X SDK have changed in many points (though most of them are nullability and changes of collection types) from iOS 8 SDK/OS X 10.10 SDK to iOS 9 SDK/OS X 10.11 SDK.


This link show a digest of the changes, but you may find many thing are not described there.

Swift in Xcode 7.0 Release Notes

also check:

Document Revision History of The Swift Programming Language (Swift 2)

Revision History of Using Swift with Cocoa and Objective-C (Swift 2)


So, if you are studying Swift intending developing apps from now on, you'd better migrate to Swift 2, as soon as possible.

Thanks very much!🙂


luo

Hi


I read this thread with interest as I face the same issue : String.index does nor have a member named advancedBy


I have updated to XCode 7.0.1, (7A1001), which means I should have Swift 2 as well.


What am I missing here ?


some more context :

I have a function with a String parameter ; I want to get the substring from the second char

func f(s: String)...

// let extractRange = Range(start: advance(searchName.startIndex, 1), end: searchName.endIndex) // that was the call with swift 1.2 that worked

let extractRange = Range(start: searchName.startIndex.advanceBy(1), end: searchName.endIndex) // that's where I get the comiler error: value of type 'index' (aka 'String.CharacterView.index') has no member advanceBy

// the following seems to work, at least compile:

let extractRange = Range(start: 1, end: searchName.endIndex)


Probably I could call directly a substring, but I would like to understand what's going on here.

I'm afraid you are trapped in a simple typo: advanceBy -> advancedBy .

how to get subString from String
 
 
Q