Swift remove ONLY trailing spaces from string - string

many examples in SO are fixing both sides, the leading and trailing. My request is only about the trailing.
My input text is: " keep my left side "
Desired output: " keep my left side"
Of course this command will remove both ends:
let cleansed = messageText.trimmingCharacters(in: .whitespacesAndNewlines)
Which won't work for me.
How can I do it?

A quite simple solution is regular expression, the pattern is one or more(+) whitespace characters(\s) at the end of the string($)
let string = " keep my left side "
let cleansed = string.replacingOccurrences(of: "\\s+$",
with: "",
options: .regularExpression)

You can use the rangeOfCharacter function on string with a characterSet. This extension then uses recursion of there are multiple spaces to trim. This will be efficient if you only usually have a small number of spaces.
extension String {
func trailingTrim(_ characterSet : CharacterSet) -> String {
if let range = rangeOfCharacter(from: characterSet, options: [.anchored, .backwards]) {
return self.substring(to: range.lowerBound).trailingTrim(characterSet)
}
return self
}
}
"1234 ".trailingTrim(.whitespaces)
returns
"1234"

Building on vadian's answer I found for Swift 3 at the time of writing that I had to include a range parameter. So:
func trailingTrim(with string : String) -> String {
let start = string.startIndex
let end = string.endIndex
let range: Range<String.Index> = Range<String.Index>(start: start, end: end)
let cleansed:String = string.stringByReplacingOccurrencesOfString("\\s+$",
withString: "",
options: .RegularExpressionSearch,
range: range)
return cleansed
}

Simple. No regular expressions needed.
extension String {
func trimRight() -> String {
let c = reversed().drop(while: { $0.isWhitespace }).reversed()
return String(c)
}
}

Related

Making sure every Alphabet is in a string (Kotlin)

So I have a question where I am checking if a string has every letter of the alphabet in it. I was able to check if there is alphabet in the string, but I'm not sure how to check if there is EVERY alphabet in said string. Here's the code
fun isPangram (pangram: Array<String>) : String {
var panString : String
var outcome = ""
for (i in pangram.indices){
panString = pangram[i]
if (panString.matches(".^*[a-z].*".toRegex())){
outcome = outcome.plus('1')
}
else {outcome = outcome.plus('0')}
}
return outcome
}
Any ideas are welcomed Thanks.
I think it would be easier to check if all members of the alphabet range are in each string than to use Regex:
fun isPangram(pangram: Array<String>): String =
pangram.joinToString("") { inputString ->
when {
('a'..'z').all { it in inputString.lowercase() } -> "1"
else -> "0"
}
}
Hi this is how you can make with regular expression
Kotlin Syntax
fun isStrinfContainsAllAlphabeta( input: String) {
return input.lowercase()
.replace("[^a-z]".toRegex(), "")
.replace("(.)(?=.*\\1)".toRegex(), "")
.length == 26;
}
In java:
public static boolean isStrinfContainsAllAlphabeta(String input) {
return input.toLowerCase()
.replace("[^a-z]", "")
.replace("(.)(?=.*\\1)", "")
.length() == 26;
}
the function takes only one string. The first "replaceAll" removes all the non-alphabet characters, The second one removes the duplicated character, then you check how many characters remained.
Just to bounce off Tenfour04's solution, if you write two functions (one for the pangram check, one for processing the array) I feel like you can make it a little more readable, since they're really two separate tasks. (This is partly an excuse to show you some Kotlin tricks!)
val String.isPangram get() = ('a'..'z').all { this.contains(it, ignoreCase = true) }
fun checkPangrams(strings: Array<String>) =
strings.joinToString("") { if (it.isPangram) "1" else "0" }
You could use an extension function instead of an extension property (so it.isPangram()), or just a plain function with a parameter (isPangram(it)), but you can write stuff that almost reads like English, if you want!

Reverse every other word in string, keep punctuation Swift

So I got stuck on a coding challenge that I almost knew the answer too. And I think I have to use the subString call in Swift 4 to get it 100%. I want to reverse every OTHER word in a string, but ignore or keep the punctuation in its original place( index ).
var sample = "lets start. And not worry about proper sentences."
func reverseString(inputString: String) -> String {
let oldSentence = sample.components(separatedBy: " ")
var newSentence = ""
for index in 0...oldSentence.count - 1 {
let word = oldSentence[index]
if newSentence != "" {
newSentence += " "
}
if index % 2 == 1 {
let reverseWord = String(word.reversed())
newSentence += reverseWord
} else {
newSentence += word
}
}
return newSentence
}
reverseString(inputString: sample)
And this would be the expected output.
"lets trats. And ton worry tuoba proper secnetnes."
Notice the punctuation is not reversed.
You shouldn't use components(separatedBy: ) to split a string in words. See this article for the reason. Use enumerateSubstrings and pass in the appropriate option:
func reverseString(inputString: String) -> String {
var index = 1
var newSentence = inputString
inputString.enumerateSubstrings(in: inputString.startIndex..., options: .byWords) { substr, range, _, stop in
guard let substr = substr else { return }
if index % 2 == 0 {
newSentence = newSentence.replacingCharacters(in: range, with: String(substr.reversed()))
}
index += 1
}
return newSentence
}
print(reverseString(inputString: "lets start. And not worry about proper sentences."))
// lets trats. And ton worry tuoba proper secnetnes.
print(reverseString(inputString: "I think, therefore I'm"))
// I kniht, therefore m'I

Swift: insertContentsOf

I'm trying to use inertContentsOf to loop through and find all "\" characters and insert another "\" character in front of it. The problem is I won't always know the index if the character I need to insert.
For example, I know I want to insert "\" at index 3:
myString.insertContentsOf("\\".characters, at: myString.startIndex.advancedBy(3))
How would I do this without knowing the index?
I've tried the following for loops but haven't had any luck.
for words in inputArray {
for char in words {
if char == "\\" {
words.insertContentsOf("\\".characters, at: char)
}
}
}
at: char yells at me for trying to convert a character to an index, which I get but don't know how to fix it.
Edit: For some reason when I try and put it in a function inputArray.map doesn't get called.
func GenerateString(inputArray:[String])->String {
inputArray.map {
$0.stringByReplacingOccurrencesOfString("\\", withString: "\\\\")
}
let joiner = "|"
let joinerString = inputArray.joinWithSeparator(joiner)
return ("Result: \(joinerString)")
}
let example = ["hello", "world", "c:\Program File\Example"]
GenerateString(example)
Result:
"Hello|world|c:\Program File\Example"
Use stringByReplacingOccurrencesOfString instead:
words.stringByReplacingOccurrencesOfString("\\", withString: "\\\\")
Try stringByReplacingOccurrencesOfString:
var words: String = "c\\Program Files\\Example"
words = words.stringByReplacingOccurrencesOfString("\\", withString: "\\\\")
print("Result: \(words)")
// "Result: c\\Program Files\\Example"
or if you want to do this in a array:
let inputArray: [String] = ["hello", "world", "c\\Program Files\\Example"]
inputArray.map {
$0.stringByReplacingOccurrencesOfString("\\", withString: "\\\\")
}
print("Result: \(inputArray)")
// "Result: ["hello", "world", "c\\Program Files\\Example"]"
stringByReplacingOccurrencesOfString("\\", withString: "\\\\") line means replace \\ with \\\\ and it's exactly what you want to do. :)
Related Questions: Any way to replace characters on Swift String?
You can call enumerate() on any sequence that is a SequenceType to get the index along with the current item so you can do something like:
for (index, char) in words.enumerate()
Although you should also avoid modifying an array while looping it. Think maybe about having another array where you add normal characters to it, and in the case of \, you add \\
You can do map on your array and use stringByReplacingOccurrencesOfString
let new Array = inputArray.map {
$0.stringByReplacingOccurrencesOfString("\\", withString: "\\\\")
}

Change text of an attributed string and retain attributes in Swift

For output in a database program, I have certain text that I've inserted marks to indicate bold or italics, as well as some text that is substituted for images. For instance:
"%Important% ^All employees to the breakroom^" should have final output as:
Important All employees to the breakroom
I have code written to find the text with "%" signs around it and "^" signs, but the trouble I have now is the text outputs like:
%Important% ^All employees to the breakroom^
I'd like to remove these % and ^'s while retaining the string's formatting.
This is the code I'm using up until it breaks:
func processText(inString string: String) -> NSAttributedString {
let pattern = ["(?<=\\^).*?(?=\\^)","(?<=\\%).*?(?=\\%)","\\^", "\\%"]
let italicsRegex = NSRegularExpression(pattern: pattern[0], options: .allZeros, error: nil)
let range = NSMakeRange(0, count(string))
let italicsMatches = italicsRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult]
var attributedText = NSMutableAttributedString(string: string)
for match in italicsMatches! {
attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Oblique", size: 14.0)!, range: match.range)
}
let boldRegex = NSRegularExpression(pattern: pattern[1], options: .allZeros, error: nil)
let boldMatches = boldRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult]
for match in boldMatches! {
attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size: 14.0)!, range: match.range)
}
let removeItalicsMarksRegex = NSRegularExpression(pattern: pattern[2], options: .allZeros, error: nil)
let removeItalicsMarksMatches = removeItalicsMarksRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult]
var numberOfLoops = 0
for match in removeItalicsMarksMatches! {
attributedText.replaceCharactersInRange(match.range, withString: "")
}
return attributedText.copy() as! NSAttributedString
}
This works for the % match (but only the first character) and causes a crash on the ^ character immediately.
Any help or advice with resolving this would be appreciated. Thanks.
Martin,
I ended up using something very similar, but I decided to change the regular expression to include the ^ marks. In doing so, I was able to then clip the first and last characters of the included attributed substring with the "replaceCharactersInRange" method. This works a little better for my purposes so far because it's working from the attributed string so it doesn't screw up or remove any of its attributes.
I've attached the regex and the portion of the code that deals with italics for anyone's future reference (and thanks, again!):
func processText(inString string: String) -> NSAttributedString {
let pattern = ["\\^.*?\\^"] //Presented as an array here because in the full code there are a lot of patterns that are run.
let italicsRegex = NSRegularExpression(pattern: pattern[0], options: .allZeros, error: nil)
//In addition to building the match for this first regular expression, I also gather build the regular expressions and gather matches for all other matching patterns on the initial string ("string") before I start doing any processing.
let range = NSMakeRange(0, count(string.utf16))
let italicsMatches = italicsRegex?.matchesInString(string, options: .allZeros, range: range) as? [NSTextCheckingResult]
var attributedText = NSMutableAttributedString(string: string)
var charactersRemovedFromString = 0
for match in italicsMatches! {
let newRange = NSMakeRange(match.range.location - charactersRemovedFromString, match.range.length) // Take the updated range for when this loop iterates, otherwise this crashes.
attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Oblique", size: 12.0)!, range: newRange)
let rangeOfFirstCharacter = NSMakeRange(match.range.location - charactersRemovedFromString, 1)
attributedText.replaceCharactersInRange(rangeOfFirstCharacter, withString: "")
charactersRemovedFromString += 2
let rangeOfLastCharacter = NSMakeRange(match.range.location + match.range.length - charactersRemovedFromString, 1)
attributedText.replaceCharactersInRange(rangeOfLastCharacter, withString: "")
}
return attributedText
}
Here is a possible solution, essentially a translation of
how to catch multiple instances special indicated **characters** in an NSString and bold them in between?
from Objective-C to Swift.
The idea is to add the attributes and remove the delimiters in one loop. The shift
variable is needed to adjust the matching ranges after the first delimiters have been removed.
For the sake of simplicity, only the "^...^" processing is shown.
func processText(inString string: String) -> NSAttributedString {
let pattern = "(\\^)(.*?)(\\^)"
let regex = NSRegularExpression(pattern: pattern, options: nil, error: nil)!
var shift = 0 // number of characters removed so far
let attributedText = NSMutableAttributedString(string: string)
regex.enumerateMatchesInString(string, options: nil, range: NSMakeRange(0, count(string.utf16))) {
(result, _, _) -> Void in
var r1 = result.rangeAtIndex(1) // Location of the leading delimiter
var r2 = result.rangeAtIndex(2) // Location of the string between the delimiters
var r3 = result.rangeAtIndex(3) // Location of the trailing delimiter
// Adjust locations according to the string modifications:
r1.location -= shift
r2.location -= shift
r3.location -= shift
// Set attribute for string between delimiters:
attributedText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Oblique", size: 14.0)!, range: r2)
// Remove leading and trailing delimiters:
attributedText.mutableString.deleteCharactersInRange(r3)
attributedText.mutableString.deleteCharactersInRange(r1)
// Update offset:
shift += r1.length + r3.length
}
return attributedText.copy() as! NSAttributedString
}
Note that enumerateMatchesInString() takes an NSRange, therefore you have to compute
the number of UTF-16 characters and not the number of Swift characters.
Example:
let text = "🇩🇪😀aaa ^🇭🇰😁bbb^ 🇳🇱😆eee"
let attrText = processText(inString: text)
println(attrText)
Output:
🇩🇪😀aaa {
}🇭🇰😁bbb{
NSFont = " font-family: \"Helvetica-Oblique\"; font-weight: normal; font-style: italic; font-size: 14.00pt";
} 🇳🇱😆eee{
}
That worked for me!
extension UILabel {
func updateAttributedText(_ text: String) {
if let attributedText = attributedText {
let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText)
mutableAttributedText.mutableString.setString(text)
self.attributedText = mutableAttributedText
}
}
}

Defining a custom PURE Swift Character Set

So, using Foundation you can use NSCharacterSet to define character sets and test character membership in Strings. I would like to do so without Cocoa classes, but in a purely Swift manner.
Ideally, code could be used like so:
struct ReservedCharacters: CharacterSet {
characters "!", "#", "$", "&", ... etc.
func isMember(character: Character) -> Bool
func encodeCharacter(parameters) { accepts a closure }
func decodeCharacter(parameters) { accepts a closure }
}
This is probably a very loaded question. But I'd like to see what you Swifters think.
You can already test for membership in a character set by initializing a String and using the contains global function:
let vowels = "aeiou"
let isVowel = contains(vowels, "i") // isVowel == true
As far as your encode and decode functions go, are you just trying to get the 8-bit or 16-bit encodings for the Character? If that is the case then just convert them to a String and access there utf8 or utf16 properties:
let char = Character("c")
let a = Array(String(char).utf8)
println() // This prints [99]
Decode would take a little more work, but I know there's a function for it...
Edit: This will replace a character from a characterSet with '%' followed by the character's hex value:
let encode: String -> String = { s in
reduce(String(s).unicodeScalars, "") { x, y in
switch contains(charSet, Character(y)) {
case true:
return x + "%" + String(y.value, radix: 16)
default:
return x + String(y)
}
}
}
let badURL = "http://why won't this work.com"
let encoded = encode(badURL)
println(encoded) // prints "http://why%20won%27t%20this%20work.com"
Decoding, again, is a bit more challenging, but I'm sure it can be done...

Resources