Swift : How to get the string before a certain character?
IosSwiftIos Problem Overview
How do I get the string before a certain character in swift? The code below is how I did it in Objective C, but can't seem to perform the same task in Swift. Any tips or suggestions on how to achieve this? rangeOfString
seems to not work at all in swift (although Swift has been acting up for me again).
NSRange range = [time rangeOfString:@" "];
NSString *startDate =
[time substringToIndex:range.location];
As you can see from the code above I am able to get the string before the space character in Objective C.
Edit : If I try something like this
var string = "hello Swift"
var range : NSRange = string.rangeOfString("Swift")
I get the following error.
> Cannot convert the expression's type 'NSString' to type '(String,
> options: NSStringCompareOptions, range: Range
Not sure what I did wrong exactly or how to resolve it correctly.
Ios Solutions
Solution 1 - Ios
Use componentsSeparatedByString() as shown below:
var delimiter = " "
var newstr = "token0 token1 token2 token3"
var token = newstr.components(separatedBy: delimiter)
print (token[0])
Or to use your specific case:
var delimiter = " token1"
var newstr = "token0 token1 token2 token3"
var token = newstr.components(separatedBy: delimiter)
print (token[0])
Solution 2 - Ios
You can do the same with rangeOfString()
provided by String
class
let string = "Hello Swift"
if let range = string.rangeOfString("Swift") {
let firstPart = string[string.startIndex..<range.startIndex]
print(firstPart) // print Hello
}
You can also achieve it with your method substringToIndex()
let string = "Hello Swift"
if let range = string.rangeOfString("Swift") {
firstPart = string.substringToIndex(range.startIndex)
print(firstPart) // print Hello
}
Swift 3 UPDATE:
let string = "Hello Swift"
if let range = string.range(of: "Swift") {
let firstPart = string[string.startIndex..<range.lowerBound]
print(firstPart) // print Hello
}
Hope this can help you ;)
Solution 3 - Ios
Following up on Syed Tariq's answer: If you only want the string before the delimiter (otherwise, you receive an array [String]):
var token = newstr.components(separatedBy: delimiter).first
Solution 4 - Ios
You could use the method prefix(upTo:) in Swift 4 or above
var string = "hello Swift"
if let index = string.firstIndex(of: " ") {
let firstPart = string.prefix(upTo: index)
print(firstPart) // print hello
}
Solution 5 - Ios
Swift 5 extension
extension String {
func before(first delimiter: Character) -> String {
if let index = firstIndex(of: delimiter) {
let before = prefix(upTo: index)
return String(before)
}
return ""
}
func after(first delimiter: Character) -> String {
if let index = firstIndex(of: delimiter) {
let after = suffix(from: index).dropFirst()
return String(after)
}
return ""
}
}
let str = "n1:lolz"
str.before(first: ":") // n1
str.after(first: ":") // lolz
str.after(first: "z") // empty string
str.before(first: "n") // empty string
str.before(first: "g") // empty string
I think it makes as much sense to return an optional String
for preference (returning nil
if there isn't anything before or after the delimiter).
Solution 6 - Ios
My 2 cents :-) using Swift 3.0, similar to PHP strstr
extension String {
func strstr(needle: String, beforeNeedle: Bool = false) -> String? {
guard let range = self.range(of: needle) else { return nil }
if beforeNeedle {
return self.substring(to: range.lowerBound)
}
return self.substring(from: range.upperBound)
}
}
Usage1
"Hello, World!".strstr(needle: ",", beforeNeedle: true) // returns Hello
Usage2
"Hello, World!".strstr(needle: " ") // returns World!
Solution 7 - Ios
To mutate a String into the part until the first appearance of a specified String you could extend String like this:
extension String {
mutating func until(_ string: String) {
let components = self.components(separatedBy: string)
self = components[0]
}
}
This can be called like this then:
var foo = "Hello Swift"
foo.until(" Swift") // foo is now "Hello"
Solution 8 - Ios
If you want a solution that doesn't involve pulling in foundation, you can do it with find
and slicing:
let str = "Hello, I must be going."
if let comma = find(str, ",") {
let substr = str[str.startIndex..<comma]
// substr will be "Hello"
}
If you explicitly want an empty string in the case where no such character is found, you can use the nil-coalescing operator:
let str = "no comma"
let comma = find(str, ",") ?? str.startIndex
let substr = str[str.startIndex..<comma] // substr will be ""
Note, unlike the componentsSeparatedByString
technique, this does not require the creation of an array, and only requires scanning up to the first occurrence of the character rather than breaking the entire string up into the character-delimited array.
Solution 9 - Ios
You can use rangeOfString
, but it returns a Range<String.Index>
type, not a NSRange
:
let string = "hello Swift"
if let range = string.rangeOfString("Swift") {
print(string.substringToIndex(range.startIndex))
}
Solution 10 - Ios
let string = "Hello-world"
if let range = string.range(of: "-") {
let firstPart = string[(string.startIndex)..<range.lowerBound]
print(firstPart)
}
Output is: Hello
Solution 11 - Ios
Below is kind of a whole combo
let string = "This a string split using * and this is left."
if let range = string.range(of: "*") {
let lastPartIncludingDelimiter = string.substring(from: range.lowerBound)
print(lastPartIncludingDelimiter) // print * and this is left.
let lastPartExcludingDelimiter = string.substring(from: range.upperBound)
print(lastPartExcludingDelimiter) // print and this is left.
let firstPartIncludingDelimiter = string.substring(to: range.upperBound)
print(firstPartIncludingDelimiter) // print This a string split using *
let firstPartExcludingDelimiter = string.substring(to: range.lowerBound)
print(firstPartExcludingDelimiter) // print This a string split using
}