Related
I have the following simple code written in Swift 3:
let str = "Hello, playground"
let index = str.index(of: ",")!
let newStr = str.substring(to: index)
From Xcode 9 beta 5, I get the following warning:
'substring(to:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator.
How can this slicing subscript with partial range from be used in Swift 4?
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.
Convert Substring (Swift 3) to String Slicing (Swift 4)
Examples In Swift 3, 4:
let newStr = str.substring(to: index) // Swift 3
let newStr = String(str[..<index]) // Swift 4
let newStr = str.substring(from: index) // Swift 3
let newStr = String(str[index...]) // Swift 4
let range = firstIndex..<secondIndex // If you have a range
let newStr = = str.substring(with: range) // Swift 3
let newStr = String(str[range]) // Swift 4
Swift 5, 4
Usage
let text = "Hello world"
text[0] // H
text[...3] // "Hell"
text[6..<text.count] // world
text[NSRange(location: 6, length: 3)] // wor
Code
import Foundation
public extension String {
subscript(value: Int) -> Character {
self[index(at: value)]
}
}
public extension String {
subscript(value: NSRange) -> Substring {
self[value.lowerBound..<value.upperBound]
}
}
public extension String {
subscript(value: CountableClosedRange<Int>) -> Substring {
self[index(at: value.lowerBound)...index(at: value.upperBound)]
}
subscript(value: CountableRange<Int>) -> Substring {
self[index(at: value.lowerBound)..<index(at: value.upperBound)]
}
subscript(value: PartialRangeUpTo<Int>) -> Substring {
self[..<index(at: value.upperBound)]
}
subscript(value: PartialRangeThrough<Int>) -> Substring {
self[...index(at: value.upperBound)]
}
subscript(value: PartialRangeFrom<Int>) -> Substring {
self[index(at: value.lowerBound)...]
}
}
private extension String {
func index(at offset: Int) -> String.Index {
index(startIndex, offsetBy: offset)
}
}
Shorter in Swift 4/5:
let string = "123456"
let firstThree = String(string.prefix(3)) //"123"
let lastThree = String(string.suffix(3)) //"456"
Swift5
(Java's substring method):
extension String {
func subString(from: Int, to: Int) -> String {
let startIndex = self.index(self.startIndex, offsetBy: from)
let endIndex = self.index(self.startIndex, offsetBy: to)
return String(self[startIndex..<endIndex])
}
}
Usage:
var str = "Hello, Nick Michaels"
print(str.subString(from:7,to:20))
// print Nick Michaels
The conversion of your code to Swift 4 can also be done this way:
let str = "Hello, playground"
let index = str.index(of: ",")!
let substr = str.prefix(upTo: index)
You can use the code below to have a new string:
let newString = String(str.prefix(upTo: index))
substring(from: index) Converted to [index...]
Check the sample
let text = "1234567890"
let index = text.index(text.startIndex, offsetBy: 3)
text.substring(from: index) // "4567890" [Swift 3]
String(text[index...]) // "4567890" [Swift 4]
Some useful extensions:
extension String {
func substring(from: Int, to: Int) -> String {
let start = index(startIndex, offsetBy: from)
let end = index(start, offsetBy: to - from)
return String(self[start ..< end])
}
func substring(range: NSRange) -> String {
return substring(from: range.lowerBound, to: range.upperBound)
}
}
Example of uppercasedFirstCharacter convenience property in Swift3 and Swift4.
Property uppercasedFirstCharacterNew demonstrates how to use String slicing subscript in Swift4.
extension String {
public var uppercasedFirstCharacterOld: String {
if characters.count > 0 {
let splitIndex = index(after: startIndex)
let firstCharacter = substring(to: splitIndex).uppercased()
let sentence = substring(from: splitIndex)
return firstCharacter + sentence
} else {
return self
}
}
public var uppercasedFirstCharacterNew: String {
if characters.count > 0 {
let splitIndex = index(after: startIndex)
let firstCharacter = self[..<splitIndex].uppercased()
let sentence = self[splitIndex...]
return firstCharacter + sentence
} else {
return self
}
}
}
let lorem = "lorem".uppercasedFirstCharacterOld
print(lorem) // Prints "Lorem"
let ipsum = "ipsum".uppercasedFirstCharacterNew
print(ipsum) // Prints "Ipsum"
You can create your custom subString method using extension to class String as below:
extension String {
func subString(startIndex: Int, endIndex: Int) -> String {
let end = (endIndex - self.count) + 1
let indexStartOfText = self.index(self.startIndex, offsetBy: startIndex)
let indexEndOfText = self.index(self.endIndex, offsetBy: end)
let substring = self[indexStartOfText..<indexEndOfText]
return String(substring)
}
}
Creating SubString (prefix and suffix) from String using Swift 4:
let str : String = "ilike"
for i in 0...str.count {
let index = str.index(str.startIndex, offsetBy: i) // String.Index
let prefix = str[..<index] // String.SubSequence
let suffix = str[index...] // String.SubSequence
print("prefix \(prefix), suffix : \(suffix)")
}
Output
prefix , suffix : ilike
prefix i, suffix : like
prefix il, suffix : ike
prefix ili, suffix : ke
prefix ilik, suffix : e
prefix ilike, suffix :
If you want to generate a substring between 2 indices , use :
let substring1 = string[startIndex...endIndex] // including endIndex
let subString2 = string[startIndex..<endIndex] // excluding endIndex
I have written a string extension for replacement of 'String: subString:'
extension String {
func sliceByCharacter(from: Character, to: Character) -> String? {
let fromIndex = self.index(self.index(of: from)!, offsetBy: 1)
let toIndex = self.index(self.index(of: to)!, offsetBy: -1)
return String(self[fromIndex...toIndex])
}
func sliceByString(from:String, to:String) -> String? {
//From - startIndex
var range = self.range(of: from)
let subString = String(self[range!.upperBound...])
//To - endIndex
range = subString.range(of: to)
return String(subString[..<range!.lowerBound])
}
}
Usage : "Date(1511508780012+0530)".sliceByString(from: "(", to: "+")
Example Result : "1511508780012"
PS: Optionals are forced to unwrap. Please add Type safety check wherever necessary.
If you are trying to just get a substring up to a specific character, you don't need to find the index first, you can just use the prefix(while:) method
let str = "Hello, playground"
let subString = str.prefix { $0 != "," } // "Hello" as a String.SubSequence
When programming I often have strings with just plain A-Za-z and 0-9. No need for difficult Index actions. This extension is based on the plain old left / mid / right functions.
extension String {
// LEFT
// Returns the specified number of chars from the left of the string
// let str = "Hello"
// print(str.left(3)) // Hel
func left(_ to: Int) -> String {
return "\(self[..<self.index(startIndex, offsetBy: to)])"
}
// RIGHT
// Returns the specified number of chars from the right of the string
// let str = "Hello"
// print(str.left(3)) // llo
func right(_ from: Int) -> String {
return "\(self[self.index(startIndex, offsetBy: self.length-from)...])"
}
// MID
// Returns the specified number of chars from the startpoint of the string
// let str = "Hello"
// print(str.left(2,amount: 2)) // ll
func mid(_ from: Int, amount: Int) -> String {
let x = "\(self[self.index(startIndex, offsetBy: from)...])"
return x.left(amount)
}
}
Hope this will help little more :-
var string = "123456789"
If you want a substring after some particular index.
var indexStart = string.index(after: string.startIndex )// you can use any index in place of startIndex
var strIndexStart = String (string[indexStart...])//23456789
If you want a substring after removing some string at the end.
var indexEnd = string.index(before: string.endIndex)
var strIndexEnd = String (string[..<indexEnd])//12345678
you can also create indexes with the following code :-
var indexWithOffset = string.index(string.startIndex, offsetBy: 4)
with this method you can get specific range of string.you need to pass start index and after that total number of characters you want.
extension String{
func substring(fromIndex : Int,count : Int) -> String{
let startIndex = self.index(self.startIndex, offsetBy: fromIndex)
let endIndex = self.index(self.startIndex, offsetBy: fromIndex + count)
let range = startIndex..<endIndex
return String(self[range])
}
}
This is my solution, no warning, no errors, but perfect
let redStr: String = String(trimmStr[String.Index.init(encodedOffset: 0)..<String.Index.init(encodedOffset: 2)])
let greenStr: String = String(trimmStr[String.Index.init(encodedOffset: 3)..<String.Index.init(encodedOffset: 4)])
let blueStr: String = String(trimmStr[String.Index.init(encodedOffset: 5)..<String.Index.init(encodedOffset: 6)])
var str = "Hello, playground"
let indexcut = str.firstIndex(of: ",")
print(String(str[..<indexcut!]))
print(String(str[indexcut!...]))
You can try in this way and will get proper results.
the simples way that I use is :
String(Array(str)[2...4])
Swift 4, 5, 5+
Substring from Last
let str = "Hello World"
let removeFirstSix = String(str.dropFirst(6))
print(removeFirstSix) //World
Substring from First
let removeLastSix = String(str.dropLast(6))
print(removeLastSix) //Hello
Hope it would be helpful.
extension String {
func getSubString(_ char: Character) -> String {
var subString = ""
for eachChar in self {
if eachChar == char {
return subString
} else {
subString += String(eachChar)
}
}
return subString
}
}
let str: String = "Hello, playground"
print(str.getSubString(","))
I want to be able to capitalizes characters from a string from an array of indexes.
let string = "format"
let indexes = [0, 5]
Expected: "FormaT"
Can this be accomplished in Swift?
You can try and get an array of the characters, and uppercase the ones in your indexes array like this:
let string = "format"
let indexes = [0, 5]
var array = string.map{ String($0) }
indexes.forEach{ array[$0] = array[$0].uppercased() }
let fixedString = array.joined()
print(fixedString)
The following String extension should work for you.
extension String {
func capitalized(at characters: [Int]) -> String {
var formattedString = self
for character in characters {
formattedString = formattedString.prefix(character) + String(self[index(startIndex, offsetBy: character)]).capitalized + formattedString.dropFirst(character + 1)
}
return formattedString
}
}
And then using it:
print("format".capitalized(at: [0,2,5]))
Result: FoRmaT
You just need to map through the String and at each character, either return the character itself or its uppercased version in case the index of the character is contained in the indices you want to modify.
extension String {
func uppercased(at indices: [Int]) -> String {
return enumerated().map { indices.contains($0.offset) ? $0.element.uppercased() : String($0.element) }.joined()
}
}
let string = "format"
let indices = [0, 5]
print(string.uppercased(at: indices)) // "FormaT"
You can iterate your indices, get the index at the desired offset and replace the subrange by its uppercase:
extension StringProtocol where Self: RangeReplaceableCollection {
mutating func uppercase(at indices: [Int]) {
for offset in indices {
let index = self.index(startIndex, offsetBy: offset)
replaceSubrange(index...index, with: self[index...index].uppercased())
}
}
func uppercased(at indices: [Int]) -> Self {
var string = self
string.uppercase(at: indices)
return string
}
}
var string = "format"
let indices = [0, 5]
string.uppercase(at: indices) // "FormaT"
string
print(string.uppercased(at: [1,2])) // "FORmaT\n"
How to mask the last string using swift, I have made the code as below. but the code only shows the last number, my expectation is that the code displays the first 5 digits
here my code:
extension StringProtocol {
var masked: String {
return String(repeating: "•", count: Swift.max(0, count-5)) + suffix(5)
} }
var name = "0123456789"
print(name.masked)
I get output: •••••56789
but my expectations: 01234•••••
Use a prefix instead of a suffix
extension StringProtocol {
var masked: String {
return prefix(5) + String(repeating: "•", count: Swift.max(0, count-5))
}
}
You could also create a function instead for parameterizing the number of digits and direction (or even the mask character)
extension StringProtocol {
func masked(_ n: Int = 5, reversed: Bool = false) -> String {
let mask = String(repeating: "•", count: Swift.max(0, count-n))
return reversed ? mask + suffix(n) : prefix(n) + mask
}
}
var name = "0123456789"
print(name.masked(5))
// 01234•••••
print(name.masked(5, reversed: true))
// •••••56789
If you have a case of wanting to mask an email address. here's the code
func maskingEmail(email: String) -> String {
let emailComponents = email.components(separatedBy: "#")
let emailDomainComponents = emailComponents[1].components(separatedBy: ".")
let maskedEmailName = String(repeating: "•", count: Swift.max(0, emailComponents[0].count-3)) + emailComponents[0].suffix(3)
let maskedEmailProvider = String(repeating: "•", count: Swift.max(0, emailDomainComponents[0].count-3)) + emailDomainComponents[0].suffix(3)
let emailDomain = emailDomainComponents[1]
return "\(maskedEmailName)#\(maskedEmailProvider).\(emailDomain)"
}
// The Output
print(maskingEmail(email: "pr1vaterelay#gmail.com")) // •••••••••lay#••ail.com
print(maskingEmail(email: "private_relay#bk.ru")) // ••••••••••lay#bk.ru
print(maskingEmail(email: "private.relay#protonmail.com")) // ••••••••••lay#•••••••ail.com
I have the following simple code written in Swift 3:
let str = "Hello, playground"
let index = str.index(of: ",")!
let newStr = str.substring(to: index)
From Xcode 9 beta 5, I get the following warning:
'substring(to:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator.
How can this slicing subscript with partial range from be used in Swift 4?
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.
Convert Substring (Swift 3) to String Slicing (Swift 4)
Examples In Swift 3, 4:
let newStr = str.substring(to: index) // Swift 3
let newStr = String(str[..<index]) // Swift 4
let newStr = str.substring(from: index) // Swift 3
let newStr = String(str[index...]) // Swift 4
let range = firstIndex..<secondIndex // If you have a range
let newStr = = str.substring(with: range) // Swift 3
let newStr = String(str[range]) // Swift 4
Swift 5, 4
Usage
let text = "Hello world"
text[0] // H
text[...3] // "Hell"
text[6..<text.count] // world
text[NSRange(location: 6, length: 3)] // wor
Code
import Foundation
public extension String {
subscript(value: Int) -> Character {
self[index(at: value)]
}
}
public extension String {
subscript(value: NSRange) -> Substring {
self[value.lowerBound..<value.upperBound]
}
}
public extension String {
subscript(value: CountableClosedRange<Int>) -> Substring {
self[index(at: value.lowerBound)...index(at: value.upperBound)]
}
subscript(value: CountableRange<Int>) -> Substring {
self[index(at: value.lowerBound)..<index(at: value.upperBound)]
}
subscript(value: PartialRangeUpTo<Int>) -> Substring {
self[..<index(at: value.upperBound)]
}
subscript(value: PartialRangeThrough<Int>) -> Substring {
self[...index(at: value.upperBound)]
}
subscript(value: PartialRangeFrom<Int>) -> Substring {
self[index(at: value.lowerBound)...]
}
}
private extension String {
func index(at offset: Int) -> String.Index {
index(startIndex, offsetBy: offset)
}
}
Shorter in Swift 4/5:
let string = "123456"
let firstThree = String(string.prefix(3)) //"123"
let lastThree = String(string.suffix(3)) //"456"
Swift5
(Java's substring method):
extension String {
func subString(from: Int, to: Int) -> String {
let startIndex = self.index(self.startIndex, offsetBy: from)
let endIndex = self.index(self.startIndex, offsetBy: to)
return String(self[startIndex..<endIndex])
}
}
Usage:
var str = "Hello, Nick Michaels"
print(str.subString(from:7,to:20))
// print Nick Michaels
The conversion of your code to Swift 4 can also be done this way:
let str = "Hello, playground"
let index = str.index(of: ",")!
let substr = str.prefix(upTo: index)
You can use the code below to have a new string:
let newString = String(str.prefix(upTo: index))
substring(from: index) Converted to [index...]
Check the sample
let text = "1234567890"
let index = text.index(text.startIndex, offsetBy: 3)
text.substring(from: index) // "4567890" [Swift 3]
String(text[index...]) // "4567890" [Swift 4]
Some useful extensions:
extension String {
func substring(from: Int, to: Int) -> String {
let start = index(startIndex, offsetBy: from)
let end = index(start, offsetBy: to - from)
return String(self[start ..< end])
}
func substring(range: NSRange) -> String {
return substring(from: range.lowerBound, to: range.upperBound)
}
}
Example of uppercasedFirstCharacter convenience property in Swift3 and Swift4.
Property uppercasedFirstCharacterNew demonstrates how to use String slicing subscript in Swift4.
extension String {
public var uppercasedFirstCharacterOld: String {
if characters.count > 0 {
let splitIndex = index(after: startIndex)
let firstCharacter = substring(to: splitIndex).uppercased()
let sentence = substring(from: splitIndex)
return firstCharacter + sentence
} else {
return self
}
}
public var uppercasedFirstCharacterNew: String {
if characters.count > 0 {
let splitIndex = index(after: startIndex)
let firstCharacter = self[..<splitIndex].uppercased()
let sentence = self[splitIndex...]
return firstCharacter + sentence
} else {
return self
}
}
}
let lorem = "lorem".uppercasedFirstCharacterOld
print(lorem) // Prints "Lorem"
let ipsum = "ipsum".uppercasedFirstCharacterNew
print(ipsum) // Prints "Ipsum"
You can create your custom subString method using extension to class String as below:
extension String {
func subString(startIndex: Int, endIndex: Int) -> String {
let end = (endIndex - self.count) + 1
let indexStartOfText = self.index(self.startIndex, offsetBy: startIndex)
let indexEndOfText = self.index(self.endIndex, offsetBy: end)
let substring = self[indexStartOfText..<indexEndOfText]
return String(substring)
}
}
Creating SubString (prefix and suffix) from String using Swift 4:
let str : String = "ilike"
for i in 0...str.count {
let index = str.index(str.startIndex, offsetBy: i) // String.Index
let prefix = str[..<index] // String.SubSequence
let suffix = str[index...] // String.SubSequence
print("prefix \(prefix), suffix : \(suffix)")
}
Output
prefix , suffix : ilike
prefix i, suffix : like
prefix il, suffix : ike
prefix ili, suffix : ke
prefix ilik, suffix : e
prefix ilike, suffix :
If you want to generate a substring between 2 indices , use :
let substring1 = string[startIndex...endIndex] // including endIndex
let subString2 = string[startIndex..<endIndex] // excluding endIndex
I have written a string extension for replacement of 'String: subString:'
extension String {
func sliceByCharacter(from: Character, to: Character) -> String? {
let fromIndex = self.index(self.index(of: from)!, offsetBy: 1)
let toIndex = self.index(self.index(of: to)!, offsetBy: -1)
return String(self[fromIndex...toIndex])
}
func sliceByString(from:String, to:String) -> String? {
//From - startIndex
var range = self.range(of: from)
let subString = String(self[range!.upperBound...])
//To - endIndex
range = subString.range(of: to)
return String(subString[..<range!.lowerBound])
}
}
Usage : "Date(1511508780012+0530)".sliceByString(from: "(", to: "+")
Example Result : "1511508780012"
PS: Optionals are forced to unwrap. Please add Type safety check wherever necessary.
If you are trying to just get a substring up to a specific character, you don't need to find the index first, you can just use the prefix(while:) method
let str = "Hello, playground"
let subString = str.prefix { $0 != "," } // "Hello" as a String.SubSequence
When programming I often have strings with just plain A-Za-z and 0-9. No need for difficult Index actions. This extension is based on the plain old left / mid / right functions.
extension String {
// LEFT
// Returns the specified number of chars from the left of the string
// let str = "Hello"
// print(str.left(3)) // Hel
func left(_ to: Int) -> String {
return "\(self[..<self.index(startIndex, offsetBy: to)])"
}
// RIGHT
// Returns the specified number of chars from the right of the string
// let str = "Hello"
// print(str.left(3)) // llo
func right(_ from: Int) -> String {
return "\(self[self.index(startIndex, offsetBy: self.length-from)...])"
}
// MID
// Returns the specified number of chars from the startpoint of the string
// let str = "Hello"
// print(str.left(2,amount: 2)) // ll
func mid(_ from: Int, amount: Int) -> String {
let x = "\(self[self.index(startIndex, offsetBy: from)...])"
return x.left(amount)
}
}
Hope this will help little more :-
var string = "123456789"
If you want a substring after some particular index.
var indexStart = string.index(after: string.startIndex )// you can use any index in place of startIndex
var strIndexStart = String (string[indexStart...])//23456789
If you want a substring after removing some string at the end.
var indexEnd = string.index(before: string.endIndex)
var strIndexEnd = String (string[..<indexEnd])//12345678
you can also create indexes with the following code :-
var indexWithOffset = string.index(string.startIndex, offsetBy: 4)
with this method you can get specific range of string.you need to pass start index and after that total number of characters you want.
extension String{
func substring(fromIndex : Int,count : Int) -> String{
let startIndex = self.index(self.startIndex, offsetBy: fromIndex)
let endIndex = self.index(self.startIndex, offsetBy: fromIndex + count)
let range = startIndex..<endIndex
return String(self[range])
}
}
This is my solution, no warning, no errors, but perfect
let redStr: String = String(trimmStr[String.Index.init(encodedOffset: 0)..<String.Index.init(encodedOffset: 2)])
let greenStr: String = String(trimmStr[String.Index.init(encodedOffset: 3)..<String.Index.init(encodedOffset: 4)])
let blueStr: String = String(trimmStr[String.Index.init(encodedOffset: 5)..<String.Index.init(encodedOffset: 6)])
var str = "Hello, playground"
let indexcut = str.firstIndex(of: ",")
print(String(str[..<indexcut!]))
print(String(str[indexcut!...]))
You can try in this way and will get proper results.
the simples way that I use is :
String(Array(str)[2...4])
Swift 4, 5, 5+
Substring from Last
let str = "Hello World"
let removeFirstSix = String(str.dropFirst(6))
print(removeFirstSix) //World
Substring from First
let removeLastSix = String(str.dropLast(6))
print(removeLastSix) //Hello
Hope it would be helpful.
extension String {
func getSubString(_ char: Character) -> String {
var subString = ""
for eachChar in self {
if eachChar == char {
return subString
} else {
subString += String(eachChar)
}
}
return subString
}
}
let str: String = "Hello, playground"
print(str.getSubString(","))
For example, if I had a string RedSox and wanted to change it to SoxRed?
I'm thinking it would be something like :
func swapString (String: String) -> String {
var stringReplaced = String
var result = stringReplaced.Select(x=> x == 'A' ? 'B' : (x=='B' ? "A" : x)).ToArray()
stringReplaced = String(result)
return stringReplaced
}
this function takes the last 3 characters of a string and appends them to the beginning, there are definitely less verbose ways of doing this but it works. it will throw an error if passed a string with < 3 characters.
import UIKit
let string = "RedSox"
func changeString ( _ string : String) -> String {
var characters : Array<Character> = []
for character in string.characters {
characters.append(character)
}
var characters2 : Array<Character> = []
var position = characters.count - 3
while position < characters.count {
characters2.append(characters[position])
position += 1
}
characters.removeLast()
characters.removeLast()
characters.removeLast()
characters2.append(contentsOf: characters)
return (String(characters2))
}
var newString = changeString(string)
print (newString)
Just use the methods which the String class already provides.
It's always a good idea putting these kind of "helper" methods in an extension.
// Define String extension
extension String {
func swappedString(count swapCount: Int) -> String {
guard self.characters.count > swapCount else {
return self
}
let index = self.index(self.endIndex, offsetBy: -swapCount)
let first = self.substring(from: index)
let second = self.substring(to: index)
return first + second
}
}
// Use it
"RedSox".swappedString(count: 3) //= SoxRed