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?
You can use the substringWithRange method. It takes a start and end String.Index.
To change the start and end index, use advancedBy(n).
You can also still use the NSString method with NSRange, but you have to make sure you are using an NSString like this:
Note: as JanX2 mentioned, this second method is not safe with unicode strings.
try this in playground
it will give you "ello, p"
However where this gets really interesting is that if you make the last index bigger than the string in playground it will show any strings that you defined after str :o
Range() appears to be a generic function so that it needs to know the type it is dealing with.
You also have to give it the actual string your interested in playgrounds as it seems to hold all stings in a sequence one after another with their variable name afterwards.
So
gives "ello, playground�str���I'm the next string�str2�"
works even if str2 is defined with a let
:)
This works in my playground :)
NOTE: @airspeedswift makes some very insightful points on the trade-offs of this approach, particularly the hidden performance impacts. Strings are not simple beasts, and getting to a particular index may take O(n) time, which means a loop that uses a subscript can be O(n^2). You have been warned.
You just need to add a new
subscript
function that takes a range and usesadvancedBy()
to walk to where you want:(This should definitely be part of the language. Please dupe rdar://17158813)For fun, you can also add a
+
operator onto the indexes:(I don't know yet if this one should be part of the language or not.)
Taking a page from Rob Napier, I developed these Common String Extensions, two of which are:
Usage:
This is how you get a range from a string:
The key point is that you are passing a range of values of type String.Index (this is what advance returns) instead of integers.
The reason why this is necessary, is that strings in Swift don't have random access (because of variable length of Unicode characters basically). You also can't do
str[1]
. String.Index is designed to work with their internal structure.You can create an extension with a subscript though, that does this for you, so you can just pass a range of integers (see e.g. Rob Napier's answer).