This works
let replaced = String(map(aString.generate()) {
$0 == " " ? "-" : $0 })
and this doesn't
let replaced = String(map(aString.generate()) {
$0 == " " ? "" : $0 })
Why?
For Swift 5:
" spaces here ".replacingOccurrences(of: " ", with: "")
returns:
"spaceshere"
Enumerating a string gives a sequence of characters, so $0 inside
the closure has the type Character. This compiles
{ $0 == " " ? "-" : $0 }
because "-" in this context is interpreted as a character literal
and therefore of the same type as $0. But
{ $0 == " " ? "" : $0 }
does not compile because "" is not a character literal (and in the conditional expression a ? b : c the operands b and c
must have the same type).
You can fix that by converting $0 to a string:
{ $0 == " " ? "" : String($0) }
but now the mapping returns an array of strings instead
of an array of characters. So instead
of the String() constructor you have to join the results:
let replaced = "".join(map(aString) { $0 == " " ? "" : String($0) })
// Swift 2 / Xcode 7:
let replaced = "".join(aString.characters.map({ $0 == " " ? "" : String($0) }))
(Note that calling generate() explicitly is not needed.)
Of course the same result would also be achieved with
// Before Swift 3.0
let replaced = aString.stringByReplacingOccurrencesOfString(" ", withString: "")
// After Swift 3.0
let replaced = aString.replacingOccurrences(of: " ", with: "")
If you want to remove white space from string then just pass string with stringByReplacingOccurrencesOfString function like below,
let replacedString = string.replacingOccurrences(of: " ", with: "")
For Text Fields, you can apply directly object of UITextField,
let replacedString = textField.text!.replacingOccurrences(of: " ", with: "")
This should work as of Swift 2.2:
let replaced = String(aString.characters.filter {$0 != " "})
If you want to delete whitespaces before and after a string, which is very useful in user input forms, you can use:
let replaced = aString.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
You can apply it directly on a textfield as well.
If you want to remove all whitespaces anywhere in the String I did come up with this solution for Swift 3.0:
let number = "+000 000 000"
let nonWhiteCharacters = number.unicodeScalars.filter {
false == NSCharacterSet.whitespacesAndNewlines.contains($0)
}.map(Character.init)
let whitespacelessNumber = String(nonWhiteCharacters)
or even better (you will need generic extension on Sequence):
extension Sequence {
public func reduce<Result>(_ result: (Self) throws -> Result) rethrows -> Result {
return try result(self)
}
}
and then you can write:
let whitespacelessNumber = number.unicodeScalars.filter {
false == NSCharacterSet.whitespacesAndNewlines.contains($0)
}.map(Character.init).reduce { String($0) }
where you can also replace NSCharacterSet.whitespacesAndNewlines for any of other character sets:
NSCharacterSet.controlCharacters
NSCharacterSet.whitespaces
NSCharacterSet.whitespacesAndNewlines
NSCharacterSet.decimalDigits
NSCharacterSet.letters
NSCharacterSet.lowercaseLetters
NSCharacterSet.uppercaseLetters
NSCharacterSet.nonBaseCharacters
NSCharacterSet.alphanumerics
NSCharacterSet.decomposables
NSCharacterSet.illegalCharacters
NSCharacterSet.punctuationCharacters
NSCharacterSet.capitalizedLetters
NSCharacterSet.symbols
NSCharacterSet.newline
You are mapping thus the number of elements should be preserved. In the second case you remove elements. Your example will fail even in case you replace " " with --.
You might prefer using filter:
let replaced = String(filter(aString.generate()) { $0 != " "})
None of the previous answers where Swifty enough for me, so I ended up with this using Swift 5:
let nonWhitespaceString = String(whitespaceString.compactMap({ $0.isWhitespace ? nil : $0 })
try this one:
let strArray0 = strArray1.map { $0.stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()) }
Hope this helps
In Swift 3.0 DO as
func RemoveWhiteSpace(aString:String) -> String
{
let replaced = aString.trimmingCharacters(in: NSCharacterSet.whitespaces)
return replaced
}
And use like this
let nonWhiteSpaceStr = self.RemoveWhiteSpace(aString: "I have white Space ")
NOTE: juhan_h's answer on this question is a more succinct version if whitespace is really all you're interested in stripping out.
https://stackoverflow.com/a/57425783/5946596
Swift 5.5
All the answers are great for removing spaces but sometimes I want to remove any whitespaces and newLines throwing in _ and - ... who knows.
The following 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)").isSubset(of: characters)
? newChar : $0
}))
}
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 just spaces 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 on this question:
https://stackoverflow.com/a/33120336/5946596
I'd be interested if someone does.
See also replacing emojis: https://stackoverflow.com/a/63416058/5946596
Related
fun printRoom() {
println("Cinema: ")
val rows = 7
val columns = 8
val seats = CharArray(columns) { 'S' }.joinToString { " " }
for (i in 1..rows) {
println("$i" + " " + seats)
}
}
any help will be appreciated. Im sure this is something simple im doing but I can't figure out why this keeps printing commas instead of S's
CharArray.joinToString has these parameters, all of which are optional and have default values:
fun CharArray.joinToString(
separator: CharSequence = ", ",
prefix: CharSequence = "",
postfix: CharSequence = "",
limit: Int = -1,
truncated: CharSequence = "...",
transform: ((Char) -> CharSequence)? = null
): String
joinToString allows you to use your own separator, add your own prefix and postfix, have an optional custom limit on the joining, and have a custom string for when that limit is reached, and also optionally transform the Chars into some other String first, before joining them together.
By passing in { " " }, you pass a lambda expression that simply returns the string " ". This corresponds to the transform parameter. Kotlin thinks that you want to transform every Char to the string " " first, and then join the " " together! Because you didn’t pass the separator parameter, the default value of ”, “ is used as the separator, which is why you see a lot of commas.
What you intended on doing is passing " " as the separator parameter. Don't write a lambda:
val seats = CharArray(columns) { 'S' }.joinToString(" ")
You can also be very explicit about this and say:
val seats = CharArray(columns) { 'S' }.joinToString(separator = " ")
If you don't mind a trailing space, repeat also works:
val seats = "S ".repeat(columns)
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
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)
}
}
myText = "word 1 / word 2"
var testVar = split(myText, { $0 == "/"}, maxSplit: Int.max, allowEmptySlices: false)
This code works but it takes empty space "word 1 " when I use testVar[0]
when I write empty spaces
var testVar = split(myText, { $0 == " / "}, maxSplit: Int.max, allowEmptySlices: false)
I get an error: 'Character' is not a subtype of 'String'
Anyone who knows how to fix that?
The split() function only works on Swift strings by comparing each element of the string as a Character. To use a string to split a string, use .componentsSeparatedByString:
var testVar = myText.componentsSeparatedByString(" / ")
I made a console program, but the problem is that it doesn't allow parameters to be inserted. So I'm wondering how would I split a single string into multiple strings to achieve what I need. E.g.: text="msg Hello" would be split into textA="msg" and textB="Hello"
This is the main console code so far (just to show the idea):
if (keyboard_check_pressed(vk_enter)) {
text_console_c = asset_get_index("scr_local_"+string(keyboard_string));
if (text_console_c > -1) {
text_console+= "> "+keyboard_string+"#";
script_execute(text_console_c);
text_console_c = -1;
}
else if (keyboard_string = "") {
text_console+= ">#";
}
else {
text_console+= "> Unknown command: "+keyboard_string+"#";
};
keyboard_string = "";
}
I cant recommend spliting string with iteration by char, because when u try split very very very long string, then time to split is very long and can freeze thread for a short/long time. Game maker is single threaded for now.
This code is much faster.
string_split
var str = argument[0] //string to split
var delimiter = argument[1] // delimiter
var letDelimiter = false // append delimiter to each part
if(argument_count == 3)
letDelimiter = argument[2]
var list = ds_list_create()
var d_at = string_pos(delimiter, str)
while(d_at > 0) {
var part = string_delete(str, d_at , string_length(str))
if(letDelimiter)
part = part + delimiter
str = string_delete(str, 1, d_at)
d_at = string_pos(delimiter, str)
ds_list_add(list, part)
if(d_at == 0 && str != "")//last string without delimiter, need to add too
ds_list_add(list, str)
}
return list;
Dont forget ds_list_destroy after you iterate all strings
for example:
var splited = string_split("first part|second part", '|')
for(splited) {
//do something with each string
}
ds_list_destroy(splited)
Something like this may help, haven't tested it out but if you can follow what is going on its a good place to start.
Text = "msg Hello"
counter = 0
stringIndex = 0
for (i = 0; i < string_length(text); i++)
{
if string_char_at(text,i) == " "
{
counter++
stringIndex = 0
} else {
string_insert(string_char_at(text,i),allStrings(counter),stringIndex)
stringIndex++
}
}
allStrings should be an array containing each of the separate strings. Whenever a " " is seen the next index of allStrings starts having it's characters filled in. stringIndex is used to add the progressive characters.