How to create String split extension with regex in Swift? - swift

I wrote extension that create split method:
extension String {
func split(splitter: String) -> Array<String> {
return self.componentsSeparatedByString(splitter)
}
}
So in playground I can write:
var str = "Hello, playground"
if str.split(",").count > 1{
var out = str.split(",")[0]
println("output: \(out)") // output: Hello
}
What do I need to make it work with regex like in Java:
str.split("[ ]+")
Because this way it doesn't work.
Thanks,

First, your split function has some redundancy. It is enough to return
return self.componentsSeparatedByString(splitter)
Second, to work with a regular expression you just have to create a NSRegularExpression and then perhaps replace all occurrences with your own "stop string" and finally separate using that. E.g.
extension String {
func split(regex pattern: String) -> [String] {
let template = "-|*~~*~~*|-" /// Any string that isn't contained in the original string (self).
let regex = try? NSRegularExpression(pattern: pattern)
let modifiedString = regex?.stringByReplacingMatches(
in: self,
range: NSRange(
location: 0,
length: count
),
withTemplate: template /// Replace with the template/stop string.
)
/// Split by the replaced string.
return modifiedString?.components(separatedBy: template) ?? []
}
}

Related

How do I remove dashes, parentheses, and spaces from a phone number? [duplicate]

Using only swift code I cant figure out how to take "(555) 555-5555" and return only the numeric values and get "5555555555". I need to remove all the parentheses, white spaces, and the dash. The only examples I can find are in objective-C and they seem to all use the .trim() method. It appears as though swift doesn't have this method but it does have the .stringByTrimmingCharacters method, but that only seems to trim the white spaces before and after the data.
Swift 3 & 4
extension String {
var digits: String {
return components(separatedBy: CharacterSet.decimalDigits.inverted)
.joined()
}
}
Swift 5
You should be able to omit return
Also:
Read the comment from #onmyway133 for a word of caution
Split the string by non-digit characters to an array of digits and the join them back to a string:
Swift 1:
let stringArray = origString.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = NSArray(array: stringArray).componentsJoinedByString("")
Swift 2:
let stringArray = origString.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = stringArray.joinWithSeparator("")
Swift 3 & 4:
let newString = origString
.components(separatedBy:CharacterSet.decimalDigits.inverted)
.joined()
I like regular expressions:
var s = "(555) 555-5555"
s = s.stringByReplacingOccurrencesOfString(
"\\D", withString: "", options: .RegularExpressionSearch,
range: s.startIndex..<s.endIndex)
In Swift 4 the solution is more nice:
import Foundation
let sourceText = "+5 (555) 555-5555"
let allowedCharset = CharacterSet
.decimalDigits
.union(CharacterSet(charactersIn: "+"))
let filteredText = String(sourceText.unicodeScalars.filter(allowedCharset.contains))
print(filteredText) // +55555555555
Here is #Tapani's Swift 2.0 answer as a handy String extension, (length property is not part of solution but I left it in example because it is also handy):
import Foundation
extension String {
var length : Int {
return self.characters.count
}
func digitsOnly() -> String{
let stringArray = self.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = stringArray.joinWithSeparator("")
return newString
}
}
Usage:
let phone = "(123)-123 - 1234"
print(phone.digitsOnly())
I had a similar issue but I needed to retain the decimal points. I tweaked the top answer to this:
extension String {
/// Returns a string with all non-numeric characters removed
public var numericString: String {
let characterSet = CharacterSet(charactersIn: "0123456789.").inverted
return components(separatedBy: characterSet)
.joined()
}
}
Details
Xcode Version 10.2.1 (10E1001), Swift 5
Solution
import Foundation
extension String {
private func filterCharacters(unicodeScalarsFilter closure: (UnicodeScalar) -> Bool) -> String {
return String(String.UnicodeScalarView(unicodeScalars.filter { closure($0) }))
}
private func filterCharacters(definedIn charSets: [CharacterSet], unicodeScalarsFilter: (CharacterSet, UnicodeScalar) -> Bool) -> String {
if charSets.isEmpty { return self }
let charSet = charSets.reduce(CharacterSet()) { return $0.union($1) }
return filterCharacters { unicodeScalarsFilter(charSet, $0) }
}
func removeCharacters(charSets: [CharacterSet]) -> String { return filterCharacters(definedIn: charSets) { !$0.contains($1) } }
func removeCharacters(charSet: CharacterSet) -> String { return removeCharacters(charSets: [charSet]) }
func onlyCharacters(charSets: [CharacterSet]) -> String { return filterCharacters(definedIn: charSets) { $0.contains($1) } }
func onlyCharacters(charSet: CharacterSet) -> String { return onlyCharacters(charSets: [charSet]) }
}
Usage
let string = "23f45gdor##%#i425v wer 24 1+DWEJwi 3u09ru49w*()9uE2R_)$I#Q)_ U383q04+RFJO{dgnkvlj b`kefl;nwdl qsa`WKFSA,.E"
print("original string: \(string)")
print("only .decimalDigits: \(string.onlyCharacters(charSet: .decimalDigits))")
print("only [.lowercaseLetters, .symbols]: \(string.onlyCharacters(charSets: [.lowercaseLetters, .symbols]))")
print("remove .letters: \(string.removeCharacters(charSet: .letters))")
print("remove [.decimalDigits, .lowercaseLetters]: \(string.removeCharacters(charSets: [.decimalDigits, .lowercaseLetters]))")
Result
original string: 23f45gdor##%#i425v wer 24 1+DWEJwi 3u09ru49w*()9uE2R_)$I#Q)_ U383q04+RFJO{dgnkvlj b`kefl;nwdl qsa`WKFSA,.E
only .decimalDigits: 2345425241309499238304
only [.lowercaseLetters, .symbols]: fgdorivwer+wiuruwu$q+dgnkvljb`keflnwdlqsa`
remove .letters: 2345##%#425 24 1+ 30949*()92_)$#)_ 38304+{ `; `,.
remove [.decimalDigits, .lowercaseLetters]: ##%# +DWEJ *()ER_)$I#Q)_ U+RFJO{ `; `WKFSA,.E
(Optional) String extension
extension String {
var onlyDigits: String { return onlyCharacters(charSets: [.decimalDigits]) }
var onlyLetters: String { return onlyCharacters(charSets: [.letters]) }
}
(Optional) String extension usage
let string = "23f45gdor##%#i425v wer 24 1+DWEJwi 3u09ru49w*()9uE2R_)$I#Q)_ U383q04+RFJO{dgnkvlj b`kefl;nwdl qsa`WKFSA,.E"
print("original string: \(string)")
print(".onlyDigits: \(string.onlyDigits)")
print(".onlyLetters: \(string.onlyLetters)")
(Optional) String extension usage result
original string: 23f45gdor##%#i425v wer 24 1+DWEJwi 3u09ru49w*()9uE2R_)$I#Q)_ U383q04+RFJO{dgnkvlj b`kefl;nwdl qsa`WKFSA,.E
.onlyDigits: 2345425241309499238304
.onlyLetters: fgdorivwerDWEJwiuruwuERIQUqRFJOdgnkvljbkeflnwdlqsaWKFSAE
Try this:
let string = "(555) 555-5555"
let digitString = string.filter { ("0"..."9").contains($0) }
print(digitString) // 5555555555
Putting in extension:
extension String
{
var digitString: String { filter { ("0"..."9").contains($0) } }
}
print("(555) 555-5555".digitString) // 5555555555
You'll want to use NSCharacterSet:
Check out this NSHipster link for Swift and Obj-C implementations:
http://nshipster.com/nscharacterset/
Similar example:
var string = " Lorem ipsum dolar sit amet. "
let components = string.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceCharacterSet()).filter({!isEmpty($0)})
string = join(" ", components)
See: punctuationCharacterSet
Description:
Returns a character set containing the characters in the category of Punctuation.
Informally, this set is the set of all non-whitespace characters used to separate linguistic units in scripts, such as periods, dashes, parentheses, and so on.
#Tapani Makes a great suggestion: NSCharacterSet.decimalDigitCharacterSet().invertedSet
Here is #Tapani Swift 3.2 solution
let phno = contact.phoneNumbers[0].phoneNumber
let strarr = phno.components(separatedBy: NSCharacterSet.decimalDigits.inverted)
let newString = NSArray(array: strarr).componentsJoined(by: "")
print(newString)
I found the best solution with filter function. Please have a look into it.
let string = "(555) 555-5555"
let onlyDigits = string.filter({ (char) -> Bool in
if Int("\(char)") != nil {
return true
}
else {
return false
}
})
Not exactly answered but it looks like a number.
I used URLComponents to build the url because it strips out parenthesis and dashes automatically:
var telUrl: URL? {
var component = URLComponents()
component.scheme = "tel"
component.path = "+49 (123) 1234 - 56789"
return component.url
}
then
UIApplication.shared.open(telUrl, options: [:], completionHandler: nil)
calls +49 123 123456789

Swift - Getting only AlphaNumeric Characters from String

I'm trying to create an internal function for the String class to get only AlphaNumeric characters and return a string. I'm running into a few errors with how to convert the matches back into a string using Regex. Can someone tell me how to fix the code or if there's an easier way?
I want something like this
let testString = "_<$abc$>_"
let alphaNumericString = testString.alphaNumeric() //abc
So far I have:
extension String {
internal func alphaNumeric() -> String {
let regex = try? NSRegularExpression(pattern: "[^a-z0-9]", options: .caseInsensitive)
let string = self as NSString
let results = regex?.matches(in: self, options: [], range: NSRange(location: 0, length: string.length))
let matches = results.map {
String(self[Range($0.range, in: self)!])
}
return matches.join()
}
}
You may directly use replacingOccurrences (that removes all non-overlapping matches from the input string) with [^A-Za-z0-9]+ pattern:
let str = "_<$abc$>_"
let pattern = "[^A-Za-z0-9]+"
let result = str.replacingOccurrences(of: pattern, with: "", options: [.regularExpression])
print(result) // => abc
The [^A-Za-z0-9]+ pattern is a negated character class that matches any char but the ones defined in the class, one or more occurrences (due to + quantifier).
See the regex demo.
Try below extension:
extension String {
var alphanumeric: String {
return self.components(separatedBy: CharacterSet.alphanumerics.inverted).joined().lowercased()
}
}
Usage: print("alphanumeric :", "_<$abc$>_".alphanumeric)
Output : abc
You can also use characterset for this like
extension String {
var alphaNumeric: String {
components(separatedBy: CharacterSet.alphanumerics.inverted).joined()
}
}

Is it possible to write a Swift function that replaces only part of an extended grapheme cluster like πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘§?

I want to write a function that could be used like this:
let πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦ = "πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘§".replacingFirstOccurrence(of: "πŸ‘§", with: "πŸ‘¦")
Given how odd both this string and Swift's String library are, is this possible in Swift?
Based on the insights gained at Why are emoji characters like πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦ treated so strangely in Swift strings?, a sensible approach might be to replace Unicode scalars:
extension String {
func replacingFirstOccurrence(of target: UnicodeScalar, with replacement: UnicodeScalar) -> String {
let uc = self.unicodeScalars
guard let idx = uc.index(of: target) else { return self }
let prefix = uc[uc.startIndex..<idx]
let suffix = uc[uc.index(after: idx) ..< uc.endIndex]
return "\(prefix)\(replacement)\(suffix)"
}
}
Example:
let family1 = "πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦"
print(family1.characters.map { Array(String($0).unicodeScalars) })
// [["\u{0001F469}", "\u{200D}"], ["\u{0001F469}", "\u{200D}"], ["\u{0001F467}", "\u{200D}"], ["\u{0001F466}"]]
let family2 = family1.replacingFirstOccurrence(of: "πŸ‘§", with: "πŸ‘¦")
print(family2) // πŸ‘©β€πŸ‘©β€πŸ‘¦β€πŸ‘¦
print(family2.characters.map { Array(String($0).unicodeScalars) })
// [["\u{0001F469}", "\u{200D}"], ["\u{0001F469}", "\u{200D}"], ["\u{0001F466}", "\u{200D}"], ["\u{0001F466}"]]
And here is a possible version which locates and replaces the Unicode scalars of an arbitrary string:
extension String {
func replacingFirstOccurrence(of target: String, with replacement: String) -> String {
let uc = self.unicodeScalars
let tuc = target.unicodeScalars
// Target empty or too long:
if tuc.count == 0 || tuc.count > uc.count {
return self
}
// Current search position:
var pos = uc.startIndex
// Last possible position of `tuc` within `uc`:
let end = uc.index(uc.endIndex, offsetBy: tuc.count - 1)
// Locate first Unicode scalar
while let from = uc[pos..<end].index(of: tuc.first!) {
// Compare all Unicode scalars:
let to = uc.index(from, offsetBy: tuc.count)
if !zip(uc[from..<to], tuc).contains(where: { $0 != $1 }) {
let prefix = uc[uc.startIndex..<from]
let suffix = uc[to ..< uc.endIndex]
return "\(prefix)\(replacement)\(suffix)"
}
// Next search position:
uc.formIndex(after: &pos)
}
// Target not found.
return self
}
}
Using the range(of:options:range:locale:) the solution became quite concise:
extension String {
func replaceFirstOccurrence(of searchString: String, with replacementString: String) -> String {
guard let range = self.range(of: searchString, options: .literal) else { return self }
return self.replacingCharacters(in: range, with: replacementString)
}
}
This works by first finding the range of searchString within the instance, and if a range is found the range is replaced with replacementString. Otherwise the instance just returns itself. And, since the range(of:) method returns as soon as it finds a match, the returned range is guaranteed to be the first occurrence.
"221".replaceFirstOccurrence(of: "2", with: "3") // 321
"πŸ‘©β€πŸ‘©β€πŸ‘§β€πŸ‘¦".replaceFirstOccurrence(of: "\u{1f469}", with: "\u{1f468}") // πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦
*To clarify, the last test case converts woman-woman-girl-boy to man-woman-girl-boy.

Remove all non-numeric characters from a string in swift

I have the need to parse some unknown data which should just be a numeric value, but may contain whitespace or other non-alphanumeric characters.
Is there a new way of doing this in Swift? All I can find online seems to be the old C way of doing things.
I am looking at stringByTrimmingCharactersInSet - as I am sure my inputs will only have whitespace/special characters at the start or end of the string. Are there any built in character sets I can use for this? Or do I need to create my own?
I was hoping there would be something like stringFromCharactersInSet() which would allow me to specify only valid characters to keep
I was hoping there would be something like stringFromCharactersInSet() which would allow me to specify only valid characters to keep.
You can either use trimmingCharacters with the inverted character set to remove characters from the start or the end of the string. In Swift 3 and later:
let result = string.trimmingCharacters(in: CharacterSet(charactersIn: "0123456789.").inverted)
Or, if you want to remove non-numeric characters anywhere in the string (not just the start or end), you can filter the characters, e.g. in Swift 4.2.1:
let result = string.filter("0123456789.".contains)
Or, if you want to remove characters from a CharacterSet from anywhere in the string, use:
let result = String(string.unicodeScalars.filter(CharacterSet.whitespaces.inverted.contains))
Or, if you want to only match valid strings of a certain format (e.g. ####.##), you could use regular expression. For example:
if let range = string.range(of: #"\d+(\.\d*)?"#, options: .regularExpression) {
let result = string[range] // or `String(string[range])` if you need `String`
}
The behavior of these different approaches differ slightly so it just depends on precisely what you're trying to do. Include or exclude the decimal point if you want decimal numbers, or just integers. There are lots of ways to accomplish this.
For older, Swift 2 syntax, see previous revision of this answer.
let result = string.stringByReplacingOccurrencesOfString("[^0-9]", withString: "", options: NSStringCompareOptions.RegularExpressionSearch, range:nil).stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
Swift 3
let result = string.replacingOccurrences( of:"[^0-9]", with: "", options: .regularExpression)
You can upvote this answer.
I prefer this solution, because I like extensions, and it seems a bit cleaner to me. Solution reproduced here:
extension String {
var digits: String {
return components(separatedBy: CharacterSet.decimalDigits.inverted)
.joined()
}
}
You can filter the UnicodeScalarView of the string using the pattern matching operator for ranges, pass a UnicodeScalar ClosedRange from 0 to 9 and initialise a new String with the resulting UnicodeScalarView:
extension String {
private static var digits = UnicodeScalar("0")..."9"
var digits: String {
return String(unicodeScalars.filter(String.digits.contains))
}
}
"abc12345".digits // "12345"
edit/update:
Swift 4.2
extension RangeReplaceableCollection where Self: StringProtocol {
var digits: Self {
return filter(("0"..."9").contains)
}
}
or as a mutating method
extension RangeReplaceableCollection where Self: StringProtocol {
mutating func removeAllNonNumeric() {
removeAll { !("0"..."9" ~= $0) }
}
}
Swift 5.2 β€’ Xcode 11.4 or later
In Swift5 we can use a new Character property called isWholeNumber:
extension RangeReplaceableCollection where Self: StringProtocol {
var digits: Self { filter(\.isWholeNumber) }
}
extension RangeReplaceableCollection where Self: StringProtocol {
mutating func removeAllNonNumeric() {
removeAll { !$0.isWholeNumber }
}
}
To allow a period as well we can extend Character and create a computed property:
extension Character {
var isDecimalOrPeriod: Bool { "0"..."9" ~= self || self == "." }
}
extension RangeReplaceableCollection where Self: StringProtocol {
var digitsAndPeriods: Self { filter(\.isDecimalOrPeriod) }
}
Playground testing:
"abc12345".digits // "12345"
var str = "123abc0"
str.removeAllNonNumeric()
print(str) //"1230"
"Testing0123456789.".digitsAndPeriods // "0123456789."
Swift 4
I found a decent way to get only alpha numeric characters set from a string.
For instance:-
func getAlphaNumericValue() {
var yourString = "123456789!##$%^&*()AnyThingYouWant"
let unsafeChars = CharacterSet.alphanumerics.inverted // Remove the .inverted to get the opposite result.
let cleanChars = yourString.components(separatedBy: unsafeChars).joined(separator: "")
print(cleanChars) // 123456789AnyThingYouWant
}
A solution using the filter function and rangeOfCharacterFromSet
let string = "sld [f]34é7*˜¡"
let alphaNumericCharacterSet = NSCharacterSet.alphanumericCharacterSet()
let filteredCharacters = string.characters.filter {
return String($0).rangeOfCharacterFromSet(alphaNumericCharacterSet) != nil
}
let filteredString = String(filteredCharacters) // -> sldf34Γ©7Β΅
To filter for only numeric characters use
let string = "sld [f]34é7*˜¡"
let numericSet = "0123456789"
let filteredCharacters = string.characters.filter {
return numericSet.containsString(String($0))
}
let filteredString = String(filteredCharacters) // -> 347
or
let numericSet : [Character] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
let filteredCharacters = string.characters.filter {
return numericSet.contains($0)
}
let filteredString = String(filteredCharacters) // -> 347
Swift 4
But without extensions or componentsSeparatedByCharactersInSet which doesn't read as well.
let allowedCharSet = NSCharacterSet.letters.union(.whitespaces)
let filteredText = String(sourceText.unicodeScalars.filter(allowedCharSet.contains))
let string = "+1*(234) fds567#-8/90-"
let onlyNumbers = string.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
print(onlyNumbers) // "1234567890"
or
extension String {
func removeNonNumeric() -> String {
return self.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
}
}
let onlyNumbers = "+1*(234) fds567#-8/90-".removeNonNumeric()
print(onlyNumbers)// "1234567890"
Swift 3, filters all except numbers
let myString = "dasdf3453453fsdf23455sf.2234"
let result = String(myString.characters.filter { String($0).rangeOfCharacter(from: CharacterSet(charactersIn: "0123456789")) != nil })
print(result)
Swift 4.2
let numericString = string.filter { (char) -> Bool in
return char.isNumber
}
You can do something like this...
let string = "[,myString1. \"" // string : [,myString1. "
let characterSet = NSCharacterSet(charactersInString: "[,. \"")
let finalString = (string.componentsSeparatedByCharactersInSet(characterSet) as NSArray).componentsJoinedByString("")
print(finalString)
//finalString will be "myString1"
The issue with Rob's first solution is stringByTrimmingCharactersInSet only filters the ends of the string rather than throughout, as stated in Apple's documentation:
Returns a new string made by removing from both ends of the receiver characters contained in a given character set.
Instead use componentsSeparatedByCharactersInSet to first isolate all non-occurrences of the character set into arrays and subsequently join them with an empty string separator:
"$$1234%^56()78*9££".componentsSeparatedByCharactersInSet(NSCharacterSet(charactersInString: "0123456789").invertedSet)).joinWithSeparator("")
Which returns 123456789
Swift 3
extension String {
var keepNumericsOnly: String {
return self.components(separatedBy: CharacterSet(charactersIn: "0123456789").inverted).joined(separator: "")
}
}
Swift 4.0 version
extension String {
var numbers: String {
return String(describing: filter { String($0).rangeOfCharacter(from: CharacterSet(charactersIn: "0123456789")) != nil })
}
}
Swift 4
String.swift
import Foundation
extension String {
func removeCharacters(from forbiddenChars: CharacterSet) -> String {
let passed = self.unicodeScalars.filter { !forbiddenChars.contains($0) }
return String(String.UnicodeScalarView(passed))
}
func removeCharacters(from: String) -> String {
return removeCharacters(from: CharacterSet(charactersIn: from))
}
}
ViewController.swift
let character = "1Vi234s56a78l9"
let alphaNumericSet = character.removeCharacters(from: CharacterSet.decimalDigits.inverted)
print(alphaNumericSet) // will print: 123456789
let alphaNumericCharacterSet = character.removeCharacters(from: "0123456789")
print("no digits",alphaNumericCharacterSet) // will print: Vishal
Swift 4.2
let digitChars = yourString.components(separatedBy:
CharacterSet.decimalDigits.inverted).joined(separator: "")
Swift 3 Version
extension String
{
func trimmingCharactersNot(in charSet: CharacterSet) -> String
{
var s:String = ""
for unicodeScalar in self.unicodeScalars
{
if charSet.contains(unicodeScalar)
{
s.append(String(unicodeScalar))
}
}
return s
}
}

Any way to replace characters on Swift String?

I am looking for a way to replace characters in a Swift String.
Example: "This is my string"
I would like to replace " " with "+" to get "This+is+my+string".
How can I achieve this?
This answer has been updated for Swift 4 & 5. If you're still using Swift 1, 2 or 3 see the revision history.
You have a couple of options. You can do as #jaumard suggested and use replacingOccurrences()
let aString = "This is my string"
let newString = aString.replacingOccurrences(of: " ", with: "+", options: .literal, range: nil)
And as noted by #cprcrack below, the options and range parameters are optional, so if you don't want to specify string comparison options or a range to do the replacement within, you only need the following.
let aString = "This is my string"
let newString = aString.replacingOccurrences(of: " ", with: "+")
Or, if the data is in a specific format like this, where you're just replacing separation characters, you can use components() to break the string into and array, and then you can use the join() function to put them back to together with a specified separator.
let toArray = aString.components(separatedBy: " ")
let backToString = toArray.joined(separator: "+")
Or if you're looking for a more Swifty solution that doesn't utilize API from NSString, you could use this.
let aString = "Some search text"
let replaced = String(aString.map {
$0 == " " ? "+" : $0
})
You can use this:
let s = "This is my string"
let modified = s.replace(" ", withString:"+")
If you add this extension method anywhere in your code:
extension String
{
func replace(target: String, withString: String) -> String
{
return self.stringByReplacingOccurrencesOfString(target, withString: withString, options: NSStringCompareOptions.LiteralSearch, range: nil)
}
}
Swift 3:
extension String
{
func replace(target: String, withString: String) -> String
{
return self.replacingOccurrences(of: target, with: withString, options: NSString.CompareOptions.literal, range: nil)
}
}
Swift 3, Swift 4, Swift 5 Solution
let exampleString = "Example string"
//Solution suggested above in Swift 3.0
let stringToArray = exampleString.components(separatedBy: " ")
let stringFromArray = stringToArray.joined(separator: "+")
//Swiftiest solution
let swiftyString = exampleString.replacingOccurrences(of: " ", with: "+")
Did you test this :
var test = "This is my string"
let replaced = test.stringByReplacingOccurrencesOfString(" ", withString: "+", options: nil, range: nil)
var str = "This is my string"
print(str.replacingOccurrences(of: " ", with: "+"))
Output is
This+is+my+string
Swift 5.5
I am using this extension:
extension String {
func replaceCharacters(characters: String, toSeparator: String) -> String {
let characterSet = CharacterSet(charactersIn: characters)
let components = components(separatedBy: characterSet)
let result = components.joined(separator: toSeparator)
return result
}
func wipeCharacters(characters: String) -> String {
return self.replaceCharacters(characters: characters, toSeparator: "")
}
}
Usage:
"<34353 43434>".replaceCharacters(characters: "< >", toSeparator:"+") // +34353+43434+
"<34353 43434>".wipeCharacters(characters: "< >") // 3435343434
Swift 4:
let abc = "Hello world"
let result = abc.replacingOccurrences(of: " ", with: "_",
options: NSString.CompareOptions.literal, range:nil)
print(result :\(result))
Output:
result : Hello_world
A Swift 3 solution along the lines of Sunkas's:
extension String {
mutating func replace(_ originalString:String, with newString:String) {
self = self.replacingOccurrences(of: originalString, with: newString)
}
}
Use:
var string = "foo!"
string.replace("!", with: "?")
print(string)
Output:
foo?
A category that modifies an existing mutable String:
extension String
{
mutating func replace(originalString:String, withString newString:String)
{
let replacedString = self.stringByReplacingOccurrencesOfString(originalString, withString: newString, options: nil, range: nil)
self = replacedString
}
}
Use:
name.replace(" ", withString: "+")
Swift 3 solution based on Ramis' answer:
extension String {
func withReplacedCharacters(_ characters: String, by separator: String) -> String {
let characterSet = CharacterSet(charactersIn: characters)
return components(separatedBy: characterSet).joined(separator: separator)
}
}
Tried to come up with an appropriate function name according to Swift 3 naming convention.
Less happened to me, I just want to change (a word or character) in the String
So I've use the Dictionary
extension String{
func replace(_ dictionary: [String: String]) -> String{
var result = String()
var i = -1
for (of , with): (String, String)in dictionary{
i += 1
if i<1{
result = self.replacingOccurrences(of: of, with: with)
}else{
result = result.replacingOccurrences(of: of, with: with)
}
}
return result
}
}
usage
let mobile = "+1 (800) 444-9999"
let dictionary = ["+": "00", " ": "", "(": "", ")": "", "-": ""]
let mobileResult = mobile.replace(dictionary)
print(mobileResult) // 001800444999
Xcode 11 β€’ Swift 5.1
The mutating method of StringProtocol replacingOccurrences can be implemented as follow:
extension RangeReplaceableCollection where Self: StringProtocol {
mutating func replaceOccurrences<Target: StringProtocol, Replacement: StringProtocol>(of target: Target, with replacement: Replacement, options: String.CompareOptions = [], range searchRange: Range<String.Index>? = nil) {
self = .init(replacingOccurrences(of: target, with: replacement, options: options, range: searchRange))
}
}
var name = "This is my string"
name.replaceOccurrences(of: " ", with: "+")
print(name) // "This+is+my+string\n"
var str = "This is my string"
str = str.replacingOccurrences(of: " ", with: "+")
print(str)
This is easy in swift 4.2. just use replacingOccurrences(of: " ", with: "_") for replace
var myStr = "This is my string"
let replaced = myStr.replacingOccurrences(of: " ", with: "_")
print(replaced)
Since Swift 2, String does no longer conform to SequenceType. In other words, you can not iterate through a string with a for...in loop.
The simple and easy way is to convert String to Array to get the benefit of the index just like that:
let input = Array(str)
I remember when I tried to index into String without using any conversion. I was really frustrated that I couldn’t come up with or reach a desired result, and was about to give up.
But I ended up creating my own workaround solution, and here is the full code of the extension:
extension String {
subscript (_ index: Int) -> String {
get {
String(self[self.index(startIndex, offsetBy: index)])
}
set {
remove(at: self.index(self.startIndex, offsetBy: index))
insert(Character(newValue), at: self.index(self.startIndex, offsetBy: index))
}
}
}
Now that you can read and replace a single character from string using its index just like you originally wanted to:
var str = "cat"
for i in 0..<str.count {
if str[i] == "c" {
str[i] = "h"
}
}
print(str)
It’s simple and useful way to use it and get through Swift’s String access model.
Now that you’ll feel it’s smooth sailing next time when you can loop through the string just as it is, not casting it into Array.
Try it out, and see if it can help!
I've implemented this very simple func:
func convap (text : String) -> String {
return text.stringByReplacingOccurrencesOfString("'", withString: "''")
}
So you can write:
let sqlQuery = "INSERT INTO myTable (Field1, Field2) VALUES ('\(convap(value1))','\(convap(value2)')
I think Regex is the most flexible and solid way:
var str = "This is my string"
let regex = try! NSRegularExpression(pattern: " ", options: [])
let output = regex.stringByReplacingMatchesInString(
str,
options: [],
range: NSRange(location: 0, length: str.characters.count),
withTemplate: "+"
)
// output: "This+is+my+string"
Swift extension:
extension String {
func stringByReplacing(replaceStrings set: [String], with: String) -> String {
var stringObject = self
for string in set {
stringObject = self.stringByReplacingOccurrencesOfString(string, withString: with)
}
return stringObject
}
}
Go on and use it like let replacedString = yorString.stringByReplacing(replaceStrings: [" ","?","."], with: "+")
The speed of the function is something that i can hardly be proud of, but you can pass an array of String in one pass to make more than one replacement.
Here is the example for Swift 3:
var stringToReplace = "This my string"
if let range = stringToReplace.range(of: "my") {
stringToReplace?.replaceSubrange(range, with: "your")
}
Here's an extension for an in-place occurrences replace method on String, that doesn't no an unnecessary copy and do everything in place:
extension String {
mutating func replaceOccurrences<Target: StringProtocol, Replacement: StringProtocol>(of target: Target, with replacement: Replacement, options: String.CompareOptions = [], locale: Locale? = nil) {
var range: Range<Index>?
repeat {
range = self.range(of: target, options: options, range: range.map { self.index($0.lowerBound, offsetBy: replacement.count)..<self.endIndex }, locale: locale)
if let range = range {
self.replaceSubrange(range, with: replacement)
}
} while range != nil
}
}
(The method signature also mimics the signature of the built-in String.replacingOccurrences() method)
May be used in the following way:
var string = "this is a string"
string.replaceOccurrences(of: " ", with: "_")
print(string) // "this_is_a_string"
If you don't want to use the Objective-C NSString methods, you can just use split and join:
var string = "This is my string"
string = join("+", split(string, isSeparator: { $0 == " " }))
split(string, isSeparator: { $0 == " " }) returns an array of strings (["This", "is", "my", "string"]).
join joins these elements with a +, resulting in the desired output: "This+is+my+string".
you can test this:
let newString = test.stringByReplacingOccurrencesOfString(" ", withString: "+", options: nil, range: nil)
Swift 5.5
But this might work in earlier versions.
I'm frequently replacing because I want to replace "any whitespace or -" with a _ or something like that. This extension on string lets me do that.
extension String {
func removingCharacters(_ characters:CharacterSet) -> Self {
Self(self.unicodeScalars.filter {
!characters.contains($0)
})
}
func removingCharacters(in string:String) -> Self {
Self(self.unicodeScalars.filter {
!CharacterSet(charactersIn:string).contains($0)
})
}
func replacingCharacters(_ characters:CharacterSet, with newChar:Character) -> Self {
String(self.compactMap( {
CharacterSet(charactersIn: "\($0.1)").isSubset(of: characters)
? newChar : $0.1
}))
}
func replacingCharacters(in string:String, with newChar:Character) -> Self {
String(self.compactMap( {
CharacterSet(charactersIn: "\($0)").isSubset(of: CharacterSet(charactersIn:string))
? newChar : $0
}))
}
}
usage:
print("hello \n my name\t is Joe".removingCharacters(.whitespacesAndNewlines))
print("hello \n my name\t is Joe".removingCharacters(in: " \t\n"))
print("ban annan anann ana".replacingCharacters(.whitespacesAndNewlines, with: "_"))
print("ban-annan anann ana".replacingCharacters(in: " -", with: "_"))
Obviously for a single character the .replacingOccurrences(of: " ", with: "+") is better.
I have not done a performance comparison to the
let toArray = aString.components(separatedBy: characterSet)
let backToString = toArray.joined(separator: "+")
style done in Ramis's extension. I'd be interested if someone does.
See also replacing emoji's: https://stackoverflow.com/a/63416058/5946596