I have not yet been able to figure out how to get a substring of a String
in Swift:
var str = “Hello, playground”
func test(str: String) -> String {
return str.substringWithRange( /* What goes here? */ )
}
test (str)
I'm not able to create a Range in Swift. Autocomplete in the Playground isn’t super helpful - this is what it suggests:
return str.substringWithRange(aRange: Range<String.Index>)
I haven't found anything in the Swift Standard Reference Library that helps. Here was another wild guess:
return str.substringWithRange(Range(0, 1))
And this:
let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2)
return str.substringWithRange(r)
I've seen other answers (Finding index of character in Swift String) that seem to suggest that since String
is a bridge type for NSString
, the "old" methods should work, but it's not clear how - e.g., this doesn't work either (doesn't appear to be valid syntax):
let x = str.substringWithRange(NSMakeRange(0, 3))
Thoughts?
The short answer is that this is really hard in Swift right now. My hunch is that there is still a bunch of work for Apple to do on convenience methods for things like this.
String.substringWithRange()
is expecting aRange<String.Index>
parameter, and as far as I can tell there isn't a generator method for theString.Index
type. You can getString.Index
values back fromaString.startIndex
andaString.endIndex
and call.succ()
or.pred()
on them, but that's madness.How about an extension on the String class that takes good old
Int
s?I tried to come up with something Pythonic.
All the subscripts here are great, but the times I really need something simple is usually when I want to count from back, e.g.
string.endIndex.advancedBy(-1)
It supports
nil
values, for both start and end index, wherenil
would mean index at 0 for start,string.characters.count
for end.Full sample you can see here
If you have an
NSRange
, bridging toNSString
works seamlessly. For example, I was doing some work withUITextFieldDelegate
and I quickly wanted to compute the new string value when it asked if it should replace the range.To me, that is the really interesting part of your question. String is bridged to NSString, so most NSString methods do work directly on a String. You can use them freely and without thinking. So, for example, this works just as you expect:
But, as so often happens, "I got my mojo workin' but it just don't work on you." You just happened to pick one of the rare cases where a parallel identically named Swift method exists, and in a case like that, the Swift method overshadows the Objective-C method. Thus, when you say
str.substringWithRange
, Swift thinks you mean the Swift method rather than the NSString method — and then you are hosed, because the Swift method expects aRange<String.Index>
, and you don't know how to make one of those.The easy way out is to stop Swift from overshadowing like this, by casting explicitly:
Note that no significant extra work is involved here. "Cast" does not mean "convert"; the String is effectively an NSString. We are just telling Swift how to look at this variable for purposes of this one line of code.
The really weird part of this whole thing is that the Swift method, which causes all this trouble, is undocumented. I have no idea where it is defined; it is not in the NSString header and it's not in the Swift header either.
here is a example to get video-Id only .i.e (6oL687G0Iso) from the whole URL in swift