How do I get part of a string in swift?
Edit: This answer was from 2014 and is obsolete today, I recommend referencing Vyacheslav's answer instead
The equivalent of Left is substringToIndex
Example: (directly from this site)
let myString = "ABCDEFGHI"
let mySubstring = (myString.substringToIndex(2))
//This grabs the first 2 digits of the string and stops there,
//which returns "AB"
The (rough) equivalent of Right is substringFromIndex
Example: (directly from the same site)
let myString = "ABCDEFGHI"
let mySubstring = (myString.substringFromIndex(2))
//This jumps over the first 2 digits of the string and grabs the rest,
//which returns "CDEFGHI"
See https://web.archive.org/web/20170504165315/http://www.learnswiftonline.com/reference-guides/string-reference-guide-for-swift/
How does String substring work in Swift
All of the following examples use
var str = "Hello, playground"
Swift 4
Strings got a pretty big overhaul in Swift 4. When you get some substring from a String now, you get a Substring
type back rather than a String
. Why is this? Strings are value types in Swift. That means if you use one String to make a new one, then it has to be copied over. This is good for stability (no one else is going to change it without your knowledge) but bad for efficiency.
A Substring, on the other hand, is a reference back to the original String from which it came. Here is an image from the documentation illustrating that.
No copying is needed so it is much more efficient to use. However, imagine you got a ten character Substring from a million character String. Because the Substring is referencing the String, the system would have to hold on to the entire String for as long as the Substring is around. Thus, whenever you are done manipulating your Substring, convert it to a String.
let myString = String(mySubstring)
This will copy just the substring over and the memory holding old String can be reclaimed. Substrings (as a type) are meant to be short lived.
Another big improvement in Swift 4 is that Strings are Collections (again). That means that whatever you can do to a Collection, you can do to a String (use subscripts, iterate over the characters, filter, etc).
The following examples show how to get a substring in Swift.
Getting substrings
You can get a substring from a string by using subscripts or a number of other methods (for example, prefix
, suffix
, split
). You still need to use String.Index
and not an Int
index for the range, though. (See my other answer if you need help with that.)
Beginning of a string
You can use a subscript (note the Swift 4 one-sided range):
let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str[..<index] // Hello
or prefix
:
let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str.prefix(upTo: index) // Hello
or even easier:
let mySubstring = str.prefix(5) // Hello
End of a string
Using subscripts:
let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str[index...] // playground
or suffix
:
let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str.suffix(from: index) // playground
or even easier:
let mySubstring = str.suffix(10) // playground
Note that when using the suffix(from: index)
I had to count back from the end by using -10
. That is not necessary when just using suffix(x)
, which just takes the last x
characters of a String.
Range in a string
Again we simply use subscripts here.
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end
let mySubstring = str[range] // play
Converting Substring
to String
Don't forget, when you are ready to save your substring, you should convert it to a String
so that the old string's memory can be cleaned up.
let myString = String(mySubstring)
Using an Int
index extension?
I'm hesitant to use an Int
based index extension after reading the article Strings in Swift 3 by Airspeed Velocity and Ole Begemann. Although in Swift 4, Strings are collections, the Swift team purposely hasn't used Int
indexes. It is still String.Index
. This has to do with Swift Characters being composed of varying numbers of Unicode codepoints. The actual index has to be uniquely calculated for every string.
I have to say, I hope the Swift team finds a way to abstract away String.Index
in the future. But until then, I am choosing to use their API. It helps me to remember that String manipulations are not just simple Int
index lookups.
How do I check if a string contains another string in Swift?
You can do exactly the same call with Swift:
Swift 4 & Swift 5
In Swift 4 String is a collection of Character
values, it wasn't like this in Swift 2 and 3, so you can use this more concise code1:
let string = "hello Swift"
if string.contains("Swift") {
print("exists")
}
Swift 3.0+
var string = "hello Swift"
if string.range(of:"Swift") != nil {
print("exists")
}
// alternative: not case sensitive
if string.lowercased().range(of:"swift") != nil {
print("exists")
}
Older Swift
var string = "hello Swift"
if string.rangeOfString("Swift") != nil{
println("exists")
}
// alternative: not case sensitive
if string.lowercaseString.rangeOfString("swift") != nil {
println("exists")
}
I hope this is a helpful solution since some people, including me, encountered some strange problems by calling containsString()
.1
PS. Don't forget to import Foundation
Footnotes
- Just remember that using collection functions on Strings has some edge cases which can give you unexpected results, e. g. when dealing with emojis or other grapheme clusters like accented letters.
How to get a substring in swift 4?
String.Index
is not an integer, and you cannot simply subtracts.endIndex - 3
, as "Collections move their index", see
A New Model for Collections and Indices on Swift evolution.
Care must be taken not to move the index not beyond the valid bounds.
Example:
let s = "aString"
if let upperBound = s.index(s.endIndex, offsetBy: -3, limitedBy: s.startIndex) {
let subS = String(s[..<upperBound])
} else {
print("too short")
}
Alternatively,
let upperBound = s.index(s.endIndex, offsetBy: -3, limitedBy: s.startIndex) ?? s.startIndex
let subS = String(s[..<upperBound])
which would print an empty string if s
has less then 3 characters.
If you want the initial portion of a string then you can simply do
let subS = String(s.dropLast(3))
or as a mutating method:
var s = "aString"
s.removeLast(min(s.count, 3))
print(s) // "aStr"
Swift: Extract a Substring from a String
The regex approach to find the first 5 characters from [0-9] or [A-F] after "ID: "(used hex letters only if this is not the case you can use A-Z).
if let range = string.range(of: "(?<=ID: )[0-9A-F]{5}", options: .regularExpression) {
let id = string[range] //
// if you need a String instead of a substring
let stringID = String(string[range])
}
edit/update:
Looking at your answer it looks like the requirements are totally different from your original post anyway to find an IF compound of 8 hexa characters followed by hyphen then 4 hexa characters followed by hyphen (3 times) than 12 hexa characters you can use the following regex "([0-9a-f]{8}-)([0-9a-f]{4}-){3}([0-9a-f]{12})"
:
let dataString = """
{
"@odata.context": "$metadata#GeoFences(Points())/$entity",
"ID": "2b2a2abc-5962-4290-92b4-773025ffd50b",
"Points": {
"POINT_TYPE": "F",
"POINT_NUM": 0,
"LATITUDE": 32.92197686725423,
"LONGITUDE": -117.04306932263532,
"parent_ID": "2b2a2abc-5962-4290-92b4-773025ffd50b"
},
"GEOFENCE_NAME": "New Fence",
"GEOFENCE_TYPE": "O",
"PRIVACY": "X",
"CENTER_LAT": 32.92043316309709,
"CENTER_LONG": -117.04286922250975,
"ZOOM_LAT": 0.006238797350533787,
"ZOOM_LONG": 0.005345531926053582,
"PATH_TOLERANCE": 5,
"ENTRANCE_TOLERANCE": 5
}
"""
if let range = dataString.range(of: "([0-9a-f]{8}-)([0-9a-f]{4}-){3}([0-9a-f]{12})", options: .regularExpression) {
let id = dataString[range] // 4561E
print("ID:", id)
// if you need a String instead of a substring
let stringID = String(dataString[range])
print("stringID:", stringID)
}
This will print
ID: 2b2a2abc-5962-4290-92b4-773025ffd50b
stringID: 2b2a2abc-5962-4290-92b4-773025ffd50b
Note that your code would result in "2b2a2abc-5962-4290-92b4-773025ffd50
edit/update2:
Considering that your string is JSON you can simply decode your string id:
struct Root: Codable {
let id: String
enum CodingKeys: String, CodingKey {
case id = "ID"
}
}
do {
let id = try JSONDecoder().decode(Root.self, from: Data(dataString.utf8)).id
print(id) // "2b2a2abc-5962-4290-92b4-773025ffd50b"
} catch {
print(error)
}
If you need to decode all your data:
struct Root: Codable {
let odataContext, id: String
let points: Points
let geofenceName, geofenceType, privacy: String
let centerLat, centerLong, zoomLat, zoomLong: Double
let pathTolerance, entranceTolerance: Int
enum CodingKeys: String, CodingKey {
case odataContext = "@odata.context", id = "ID", points = "Points", geofenceName = "GEOFENCE_NAME", geofenceType = "GEOFENCE_TYPE", privacy = "PRIVACY", centerLat = "CENTER_LAT", centerLong = "CENTER_LONG", zoomLat = "ZOOM_LAT", zoomLong = "ZOOM_LONG", pathTolerance = "PATH_TOLERANCE", entranceTolerance = "ENTRANCE_TOLERANCE"
}
}
struct Points: Codable {
let pointType: String
let pointNum: Int
let latitude, longitude: Double
let parentID: String
enum CodingKeys: String, CodingKey {
case pointType = "POINT_TYPE", pointNum = "POINT_NUM", latitude = "LATITUDE", longitude = "LONGITUDE", parentID = "parent_ID"
}
}
do {
let root = try JSONDecoder().decode(Root.self, from: Data(dataString.utf8))
print("ID:", root.id) // ID: 2b2a2abc-5962-4290-92b4-773025ffd50b
print("Root:", root) // Root: Root(odataContext: "$metadata#GeoFences(Points())/$entity", id: "2b2a2abc-5962-4290-92b4-773025ffd50b", points: __lldb_expr_111.Points(pointType: "F", pointNum: 0, latitude: 32.92197686725423, longitude: -117.04306932263532, parentID: "2b2a2abc-5962-4290-92b4-773025ffd50b"), geofenceName: "New Fence", geofenceType: "O", privacy: "X", centerLat: 32.92043316309709, centerLong: -117.04286922250975, zoomLat: 0.0062387973505337885, zoomLong: 0.005345531926053582, pathTolerance: 5, entranceTolerance: 5)
} catch {
print(error)
}
How can I use String substring in Swift 4? 'substring(to:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator
You should leave one side empty, hence the name "partial range".
let newStr = str[..<index]
The same stands for partial range from operators, just leave the other side empty:
let newStr = str[index...]
Keep in mind that these range operators return a Substring
. If you want to convert it to a string, use String
's initialization function:
let newStr = String(str[..<index])
You can read more about the new substrings here.
Swift: How to get substring from start to last index of character
Just accessing backward
The best way is to use substringToIndex
combined to the endIndex
property and the advance
global function.
var string1 = "www.stackoverflow.com"
var index1 = advance(string1.endIndex, -4)
var substring1 = string1.substringToIndex(index1)
Looking for a string starting from the back
Use rangeOfString
and set options
to .BackwardsSearch
var string2 = "www.stackoverflow.com"
var index2 = string2.rangeOfString(".", options: .BackwardsSearch)?.startIndex
var substring2 = string2.substringToIndex(index2!)
No extensions, pure idiomatic Swift
Swift 2.0
advance
is now a part of Index
and is called advancedBy
. You do it like:
var string1 = "www.stackoverflow.com"
var index1 = string1.endIndex.advancedBy(-4)
var substring1 = string1.substringToIndex(index1)
Swift 3.0
You can't call advancedBy
on a String
because it has variable size elements. You have to use index(_, offsetBy:)
.
var string1 = "www.stackoverflow.com"
var index1 = string1.index(string1.endIndex, offsetBy: -4)
var substring1 = string1.substring(to: index1)
A lot of things have been renamed. The cases are written in camelCase, startIndex
became lowerBound
.
var string2 = "www.stackoverflow.com"
var index2 = string2.range(of: ".", options: .backwards)?.lowerBound
var substring2 = string2.substring(to: index2!)
Also, I wouldn't recommend force unwrapping index2
. You can use optional binding or map
. Personally, I prefer using map
:
var substring3 = index2.map(string2.substring(to:))
Swift 4
The Swift 3 version is still valid but now you can now use subscripts with indexes ranges:
let string1 = "www.stackoverflow.com"
let index1 = string1.index(string1.endIndex, offsetBy: -4)
let substring1 = string1[..<index1]
The second approach remains unchanged:
let string2 = "www.stackoverflow.com"
let index2 = string2.range(of: ".", options: .backwards)?.lowerBound
let substring3 = index2.map(string2.substring(to:))
Swift - how to get specific substring from a given string
These strings are URL representations. Create an URL
and compare the host
and get the path
for example
let host = "www.instagram.com"
if let url = URL(string: "https://www.instagram.com/myUserId12345"),
url.host == host {
let userID = String(url.path.characters.dropFirst())
print(userID)
}
It's necessary to drop the first character (a leading slash) from the path.
You can even write
let userID = url.lastPathComponent
if there are more path components and the requested information is the last one.
Get nth character of a string in Swift
Attention: Please see Leo Dabus' answer for a proper implementation for Swift 4 and Swift 5.
Swift 4 or later
The Substring
type was introduced in Swift 4 to make substrings
faster and more efficient by sharing storage with the original string, so that's what the subscript functions should return.
Try it out here
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)] }
}
To convert the Substring
into a String
, you can simply
do String(string[0..2])
, but you should only do that if
you plan to keep the substring around. Otherwise, it's more
efficient to keep it a Substring
.
It would be great if someone could figure out a good way to merge Note: This answer has been already edited, it is properly implemented and now works for substrings as well. Just make sure to use a valid range to avoid crashing when subscripting your StringProtocol type. For subscripting with a range that won't crash with out of range values you can use this implementation
these two extensions into one. I tried extending StringProtocol
without success, because the index
method does not exist there.
Why is this not built-in?
The error message says "see the documentation comment for discussion". Apple provides the following explanation in the file UnavailableStringAPIs.swift:
Subscripting strings with integers is not available.
The concept of "the
i
th character in a string" has
different interpretations in different libraries and system
components. The correct interpretation should be selected
according to the use case and the APIs involved, soString
cannot be subscripted with an integer.Swift provides several different ways to access the character
data stored inside strings.
String.utf8
is a collection of UTF-8 code units in the
string. Use this API when converting the string to UTF-8.
Most POSIX APIs process strings in terms of UTF-8 code units.
String.utf16
is a collection of UTF-16 code units in
string. Most Cocoa and Cocoa touch APIs process strings in
terms of UTF-16 code units. For example, instances of
NSRange
used withNSAttributedString
and
NSRegularExpression
store substring offsets and lengths in
terms of UTF-16 code units.
String.unicodeScalars
is a collection of Unicode scalars.
Use this API when you are performing low-level manipulation
of character data.
String.characters
is a collection of extended grapheme
clusters, which are an approximation of user-perceived
characters.
Note that when processing strings that contain human-readable text,
character-by-character processing should be avoided to the largest extent
possible. Use high-level locale-sensitive Unicode algorithms instead, for example,
String.localizedStandardCompare()
,
String.localizedLowercaseString
,
String.localizedStandardRangeOfString()
etc.
How to get substring with specific ranges in Swift 4?
You can search for substrings using range(of:)
.
import Foundation
let greeting = "Hello there world!"
if let endIndex = greeting.range(of: "world!")?.lowerBound {
print(greeting[..<endIndex])
}
outputs:
Hello there
EDIT:
If you want to separate out the words, there's a quick-and-dirty way and a good way. The quick-and-dirty way:
import Foundation
let greeting = "Hello there world!"
let words = greeting.split(separator: " ")
print(words[1])
And here's the thorough way, which will enumerate all the words in the string no matter how they're separated:
import Foundation
let greeting = "Hello there world!"
var words: [String] = []
greeting.enumerateSubstrings(in: greeting.startIndex..<greeting.endIndex, options: .byWords) { substring, _, _, _ in
if let substring = substring {
words.append(substring)
}
}
print(words[1])
EDIT 2: And if you're just trying to get the 7th through the 11th character, you can do this:
import Foundation
let greeting = "Hello there world!"
let startIndex = greeting.index(greeting.startIndex, offsetBy: 6)
let endIndex = greeting.index(startIndex, offsetBy: 5)
print(greeting[startIndex..<endIndex])
Related Topics
File Couldn't Be Opened Because You Don't Have Permission to View It Error
Left Aligned Horizontal Stackview and Top Aligned Vertical Stackview
Swift Repl: How to Save/Load the Repl State? (A.K.A. Suspend/Resume, Snapshot, Clone)
How to Get Frame Data in Apprtc iOS App for Video Modifications
Swiftui Button Interact with Map
How to Change Its Own Button Image on Tap in Swift
Swift Protocol as Generic Parameter
Xcode 8 Swift 3 Pitch-Altering Sounds
Error "No Such Module" When Installed Framework with Pod in Swift 3
How to Repeat Animation Forever in Swift (Huge_Valf)
Compile Time Key Path Checking in Swift
Swift, Error Exc_Breakpoint (Code=1, Subcode=0X100695474)
Swift Array to Array of Tuples