Remove whitespaces from a string - swift

I referred this SO post to remove whitespaces and newline characters from a string. But in my string, I may have extra whitespaces as well as extra newline characters. I want to remove the unnecessary \n's and whitespaces from that string.
But if there is a string like so..."This \n is a st\tri\rng" then I don't want Thisisastring as the result but instead something like this..
This is a string

To replace contiguous spaces with a single space, replace Regular Expression \s+ with a single space:
let str = "This \n\n is a string"
if let regex = try? NSRegularExpression(pattern: "\\s+", options: NSRegularExpression.Options.caseInsensitive)
{
let result = regex.stringByReplacingMatches(in: str, options: [], range: NSMakeRange(0, str.count), withTemplate: " ")
print(result) //output: "This is a string"
}

Related

Create an NSPredicate with a line break as part of a string

I need to create a predicate that will look for the following string:
"fred\n5" where \n is a newline.
At least, this is string that is returned when reading the metadata back
You can do it with Regular Expression
let string = """
fred
5
"""
let predicate = NSPredicate(format: "self MATCHES %#", "fred\\n5")
predicate.evaluate(with: string) // true
It's also possible to use the pattern fred(\\n|\\r)5, it considers both linefeed and return.
Alternatively remove the newline character (actually any whitespace and newline characters)
let trimmedString = string.replacingOccurrences(of: "\\s", with: "", options: .regularExpression)

Regex replace spaces at each new lines

I am saving users input to db as a string and I would like to remove all spaces at each lines.
Input from user:
Hi!
My name is:
Bob
I am from the USA.
I want to remove spaces between "Bob", so the result will be:
Hi!
My name is:
Bob
I am from the USA.
I am trying to do it with the following code
let regex = try! NSRegularExpression(pattern: "\n[\\s]+", options: .caseInsensitive)
a = regex.stringByReplacingMatches(in: a, options: [], range: NSRange(0..<a.utf16.count), withTemplate: "\n")
but this code replace multiple new lines "\n", I don't want to do it.
After I run the above code: "1\n\n\n 2" -> "1\n2". The result I need: "1\n\n\n2" (only spaces are removed, not new lines).
No need for regex, split the string on the new line character into an array and then trim all lines and join them together again
let trimmed = string.components(separatedBy: .newlines)
.map { $0.trimmingCharacters(in: .whitespaces) }
.joined(separator: "\n")
or you can use reduce
let trimmed = string.components(separatedBy: .newlines)
.reduce(into: "") { $0 += "\($1.trimmingCharacters(in: .whitespaces))\n"}
You can use
let regex = try! NSRegularExpression(pattern: "(?m)^\\h+", options: .caseInsensitive)
Actually, as there are no case chars in the pattern, you may remove .caseInsensitive and use:
let regex = try! NSRegularExpression(pattern: "(?m)^\\h+", options: [])
See the regex demo. The pattern means:
(?m) - turn on multiline mode
^ - due to (?m), it matches any line start position
\h+ - one or more horizontal whitespaces.
Swift code example:
let txt = "Hi!\n\nMy name is:\n Bob\n\nI am from the USA."
let regex = "(?m)^\\h+"
print( txt.replacingOccurrences(of: regex, with: "", options: [.regularExpression]) )
Output:
Hi!
My name is:
Bob
I am from the USA.

Adding text to string

I am styling some dynamic markdown, however the framework I am using for styling doesnt support nested tags for links.
I need to parse the string and close the styling markdown tags effectively this :
"__Some bold text [FIRST LINK](https://FIRSTLINK.COM \"FIRST LINK\"), more bold text.__\n\n additional text \n\n
*some italic text[SECOND LINK](https://SECONDLINK.COM) ending text,*"
to this:
"__Some bold text __[FIRST LINK](https://FIRSTLINK.COM \"FIRST LINK\")__, more bold text.__\n\n additional text \n\n
*some italic text*[SECOND LINK](https://SECONDLINK.COM)* ending text,*"
This is only really going to be for bold and italic text. I started going down the route of
var str = "__Some bold text [FIRST LINK](https://FIRSTLINK.COM \"FIRST LINK\"), more bold text.__\n\n additional text \n\n *some italic text[SECOND LINK](https://SECONDLINK.COM) ending text,*"
let bold = str.components(separatedBy: "__")
for var string in bold {
if let matchedIndex = string.index(of: "[") {
string.insert(contentsOf: "__", at: matchedIndex)
}
}
But wondered, is there a better way to do this in Swift?
Edit - for clarity - essentially I need to modify the existing string to have closed tags prior to a link tag and re opened after a link tag - this prevents the links from being nested with the style tags and allows the styler framework to apply attributed strings accordingly
EDIT --- in line with #Linus comment here is the results of the regex (note running these out side of an extension in order to be able to test in a playground
var str = "__Some bold text [FIRST LINK](https://FIRSTLINK.COM \"FIRST LINK\"), more bold text.__\n additional text \n *some italic text[SECOND LINK](https://SECONDLINK.COM) ending text,*\n__sfdadhfjkh [THIRD LINK](https://THIRDLINK.COM \"THIRD LINK\"), more bold text.__"
do {
var regex = try NSRegularExpression(pattern: "(\\[.*?\\))" , options: [.caseInsensitive])
var newString = regex.stringByReplacingMatches(in: str, options: [], range: NSMakeRange(0, str.utf16.count), withTemplate: "__$1__")
print("\nFirst regex __$1__ \n\n\(newString)")
regex = try NSRegularExpression(pattern: "(\\[.*?\\))" , options: [.caseInsensitive])
var newerString = regex.stringByReplacingMatches(in: str, options: [], range: NSMakeRange(0, str.utf16.count), withTemplate: "*$1*")
print("\nSecond Regex *$1* \n\n"+newerString)
} catch { print("ERROR: searchFor regex (\("(\\[.*?\\))")) on string (\(str)) failed") }
Printed results
First regex __$1__
__Some bold text __[FIRST LINK](https://FIRSTLINK.COM "FIRST LINK")__, more bold text.__
additional text
*some italic text__[SECOND LINK](https://SECONDLINK.COM)__ ending text,*
__sfdadhfjkh __[THIRD LINK](https://THIRDLINK.COM "THIRD LINK")__, more bold text.__
Second Regex *$1*
__Some bold text *[FIRST LINK](https://FIRSTLINK.COM "FIRST LINK")*, more bold text.__
additional text
*some italic text*[SECOND LINK](https://SECONDLINK.COM)* ending text,*
__sfdadhfjkh *[THIRD LINK](https://THIRDLINK.COM "THIRD LINK")*, more bold text.__
I need to have both Italic and strong tags amended on the same string in order to pass it to a view to be styled
I'm using the following String extension that allows you to find strings that match a certain regex pattern and replace it with some other string:
extension String {
mutating func replaceOccurrence(ofPattern pattern: String, with replacementString: String) {
do {
let regex = try NSRegularExpression(pattern: pattern, options: [.caseInsensitive])
self = regex.stringByReplacingMatches(in: self, options: [], range: NSMakeRange(0, utf16.count), withTemplate: replacementString)
} catch { print("ERROR: searchFor regex (\(pattern)) on string (\(self)) failed") }
}
}
Then, you could replace (\[.*?\)) with __$1__, like this:
str.replaceOccurrence(ofPattern: "(\\[.*?\\))", with: "__$1__")
Explanation
...in case you're unfamiliar with regular expressions:
The regex:
( - opening parenthesis, that creates a new group which is later used to insert the matched string back into the replacement string
\[ - matches a bracket; needs to be escaped using \ to disable the bracket's regex meaning & match the actual character instead
.* - matches any character...
? - ...until...
\) - ...the next closing parenthesis; this one also needs to be escaped to match the actual character, and not create a new group
) - closes the group
The replacement:
__ - your replacement string: opening bold range in this case
$1 - inserts the previously matched group here
__ - again, your replacement string: closing bold range in this case
Fun-Fact: in Swift, you need to escape escaping characters, like \\ to make sure the code compiles, because Xcode thinks, you're trying to escape a character from the string at compile-time.
That's why the regex isn't (\[.*?\)), but (\\[.*?\\)).

swift how to convert special unicode

let result = ["response": response,
"callbackId": callbackId]
do {
let data = try NSJSONSerialization.dataWithJSONObject(result, options: .PrettyPrinted)
var str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String
str = str?.stringByReplacingOccurrencesOfString("\\", withString: "\\\\")
str = str?.stringByReplacingOccurrencesOfString("\"", withString: "\\\"")
str = str?.stringByReplacingOccurrencesOfString("\'", withString: "\\\'")
str = str?.stringByReplacingOccurrencesOfString("\n", withString: "\\n")
str = str?.stringByReplacingOccurrencesOfString("\r", withString: "\\r")
// str = str?.stringByReplacingOccurrencesOfString("\f", withString: "\\f")
// str = str?.stringByReplacingOccurrencesOfString("\u2028", withString: "\\u2028")
// str = str?.stringByReplacingOccurrencesOfString("\u2029", withString: "\\u2029")
return "bridge.invokeJs('{\"response\" : {\"username\" : \"zhongan\"},\"callbackId\" : \(callbackId)}')"
} catch {
return nil
}
I want to convert the json string to js script, and then call evaluateJavaScript, but can not convert the special character, like \f \u2029, this will give a compiler error and I don't know why.
Have a look at Strings and Characters Section Special Characters in String Literals.
According to this page \f is not defined.
The escaped special characters \0 (null character), \ (backslash), \t
(horizontal tab), \n (line feed), \r (carriage return), \" (double
quote) and \' (single quote)
An arbitrary Unicode scalar, written as
\u{n}, where n is a 1–8 digit hexadecimal number with a value equal to
a valid Unicode code point
So
\f Form Feed you may be written in escaped form as \u{000C}
\u2029 Page Feed has to be escaped as \u{2029}
\u2028 Line Separator has to be escaped as \u{2028}
See also "Unicode Control Characters"

Remove last punctuation of a swift string

I'm trying to remove the last punctuation of a string in swift 2.0
var str: String = "This is a string, but i need to remove this comma, \n"
var trimmedstr: String = str.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
First I'm removing the the white spaces and newline characters at the end, and then I need to check of the last character of trimmedstr if it is a punctuation. It can be a period, comma, dash, etc, and if it is i need to remove it it.
How can i accomplish this?
There are multiple ways to do it. You can use contains to check if the last character is in the set of expected characters, and use dropLast() on the String to construct a new string without the last character:
let str = "This is a string, but i need to remove this comma, \n"
let trimmedstr = str.trimmingCharacters(in: .whitespacesAndNewlines)
if let lastchar = trimmedstr.last {
if [",", ".", "-", "?"].contains(lastchar) {
let newstr = String(trimmedstr.dropLast())
print(newstr)
}
}
Could use .trimmingCharacters(in:.whitespacesAndNewlines) and .trimmingCharacters(in: .punctuationCharacters)
for example, to remove whitespaces and punctuations on both ends of the String-
let str = "\n This is a string, but i need to remove this comma and whitespaces, \t\n"
let trimmedStr = str.trimmingCharacters(in:
.whitespacesAndNewlines).trimmingCharacters(in: .punctuationCharacters)
Result -
This is a string, but i need to remove this comma and whitespaces