How to write a Swift String Characters.reverse function in 2021 - swift

//MARK: - Reverse every other word
var sampleSentence = "Hey my name is Chris, what is yours?"
func reverseWordsInSentence(sentence: String) -> String {
let allWords = sentence.components(separatedBy: " ")
var newSentence = ""
for word in allWords {
if newSentence != "" {
newSentence += " "
}
let reverseWord = String(word//.characters.reverse()) //Problem
newSentence += word
}
return newSentence
}
I made a tutorial by "Lets Build That App" on YouTube but his video is from 2016. He wrote it like you can see above but the characters function of the String doesn't exist!

There is a few issues regarding the Swift version of that tutorial. First the character property from string has been removed. Second collection reverse method has been renamed to reversed. Third that logic is flawed because it would reverse the punctuations after the words. You can use string enumerateSubstrings in range, use byWords option, to get the range of the words in the sentence and reverse each word as follow:
func reverseWordsInSentence(sentence: String) -> String {
var sentence = sentence
sentence.enumerateSubstrings(in: sentence.startIndex..., options: .byWords) { _, range, _, _ in
sentence.replaceSubrange(range, with: sentence[range].reversed())
}
return sentence
}
var sampleSentence = "Hey my name is Chris, what is yours?"
reverseWordsInSentence(sentence: sampleSentence) // "yeH ym eman si sirhC, tahw si sruoy?"

try this for reverse:
let reverseWord = String(word.reversed())
newSentence += reverseWord
instead of:
let reverseWord = String(word)//.characters.reverse()) //Problem
newSentence += word
output:

Related

how to convert hashtag in swift?

I want to extract the hashtag.
func getHashtags() -> [String] {
let words = components(separatedBy: " ")
var hashTags = [String]()
for word in words{
if word.hasPrefix("#"){
let hashtag = word.dropFirst()
hashTags.append(String(hashtag))
}
}
return hashTags
}
This method was not a good solution. "I want to eat #rice #eat." Hashtags are extracted well from sentences like
But if the sentence is like this,
Hashtags do not recognize line breaks, so the entire hashtag is not extracted. How can you solve this error? Tell me about the function that extracts the hashtag.
You can reformat your code for something like this. string here is your original text
func getHashtags() -> [String] {
var words = string.components(separatedBy: "#") // Separate words by #
var hashTags = [String]()
// Check if the first word of sentence is a hashtag. If it is not then remove the first word
// ex "firstWord #firstHashtag". Here "firstWord " should be removed
var shouldRemoveFirstWord = !string.hasPrefix("#")
if shouldRemoveFirstWord {
words.removeFirst()
}
for word in words{
let trimmedWord = word.trim()
// If the word has space then get only the first word
let firstWord = word.components(separatedBy: " ")
let hashtag = firstWord[0]
hashTags.append(String(hashtag))
}
return hashTags
}
And for the trim function, you can add it like this
extension String {
func trim() -> String {
return self.trimmingCharacters(in: .whitespacesAndNewlines)
}
}

Return a the matched words as string from two different string in Swift

I have: str1 = "this is the first day in my work" and str2 = "this is a great day" and I want to return the matched words as string from the previous two strings str1 & str2 and then store them in a new variable
The new variable str3: String should have this text "this is day"
I have found this in my searching but i need to return a string with matches ..
func isAnagram() -> Bool {
let str1 = "this is the first day in my work"
let str2 = "this is a great day"
func countedSet(string: String) -> NSCountedSet {
let array = string.map { (character) -> String in
return String(character)
}
return NSCountedSet(array: array)
}
return countedSet(string: str1).isEqual(countedSet(string: str2))
}
If order in the final string doesn't matter, this would be an easy solution:
let str1 = "this is the first day in my work"
let str2 = "this is a great day"
let words1 = Set(str1.split(separator: " "))
let words2 = Set(str2.split(separator: " "))
let str3 = words1.intersection(words2).reduce("") { $0 + $1 + " "}
If order matters:
...
let str3 = words1.intersection(words2).sorted {
words1.index(of: $0)! < words1.index(of: $1)!
}.reduce("") { $0 + $1 + " "}
You can use String method enumerateSubstrings(in: Range) using .byWords options to get the words in your string sentences and use filter to remove the words no contained in the second string:
extension StringProtocol where Index == String.Index {
var words: [String] {
var result: [String] = []
enumerateSubstrings(in: startIndex..., options: .byWords) { (substring, _, _, _) in
result.append(substring!)
}
return result
}
func matchingWords(in string: String) -> [String] {
return string.words.filter(words.contains)
}
}
Note that this preserves the order of occurrences and doesn't fail if there is punctuation in the string:
let str1 = "this is the first day in my work"
let str2 = "this is a great day"
let matchingWords = str1.matchingWords(in: str2) // ["this", "is", "day"]
let str3 = matchingWords.joined(separator: " ") // "this is day"

Remove stop words from a string without trimming other words in Swift

I am using the following code to remove Stop words from string but it ends up trimming other words, I just want to remove the specific words from a string without trimming other words.
import Foundation
var sentence = "God have created the creatures at his best"
let wordToRemove = "at"
if let range = sentence.range(of: wordToRemove) {
sentence.removeSubrange(range)
}
print(sentence) // God have creed the creures his best
First write an extenstion of Build-In class String
extension String {
func contains(word : String) -> Range<String.Index>?
{
return self.range(of: "\\b\(word)\\b", options: .regularExpression)
}
}
Then write the below code to remove the specific word from a sentence
var sentence = "God have created the creatures at his best"
let wordToRemove = "at"
if let range = sentence.contains(word: wordToRemove) {
sentence.removeSubrange(range)
print(sentence)
}
//Output : God have created the creatures his best
By my understanding of stop words, they can occur at any point in the sentence, including as the first or last word. So a solution should support removing them anywhere in the sentence.
import Foundation
var sentence = "at God have created the creatures at his best at"
let wordsToRemove = ["at", "his"]
let words = sentence.components(separatedBy: " ")
sentence = words.filter({ wordsToRemove.contains($0) == false }).joined(separator:" ")
// sentence is now "God have created the creatures best"
import Foundation
var sentence = "God have created the creatures at at at at his best"
let words = [" at ", " his "]
var index = 0
while index < words.count {
let word = words[index]
if let range = sentence.range(of: word) {
sentence = sentence.replacingOccurrences(of: word, with: " ", options: [], range: range)
} else {
index += 1
}
}
print(sentence)
God have created the creatures best
func replaceText(){
var sentence = "At God have created the creatures at his best aatckkat at."
var arr = [String]()
sentence.enumerateSubstrings(in: sentence.startIndex..<sentence.endIndex, options: .byWords) { (str, r1, r2, stop) in
//Condition for words to be removed
if str! != "at" && str! != "At"{
arr.append(str!)
}
}
sentence = ""
for word in arr{
sentence += "\(word) "
}
print("new altered sentence -> \(sentence)")
}
You can try this way out.

Cannot use mutating member on immutable value inside a closure

I try to capitalize the first letter of each word of a string, and I have the following code:
func makeHeadline(string: String) -> String {
let headline = words.map { (word) -> String in
var word = word
let firstCharacter = word.remove(at: word.startIndex)
return "\(String(firstCharacter).uppercased())\(word)"
}.joined(separator: " ")
return headline
}
However, I get the following error:
Cannot use mutating member on immutable value: 'word' is a 'let' constant.
I tried adding var before word (var word), but I get the error:
Parameters may not have the 'var' specifier.
How can I solve this?
Make a local mutable copy:
func makeHeadline(string: String) -> String {
let words = string.components(separatedBy: " ")
let headline = words.map { (word) -> String in
var word = word
let firstCharacter = word.removeAtIndex(word.startIndex)
return String(firstCharacter).uppercaseString + word
}.joined(separator: " ")
return headline
}

swift: how can I delete a specific character?

a string such as ! !! yuahl! ! , I want delete ! and , when I code like this
for index in InputName.characters.indices {
if String(InputName[index]) == "" || InputName.substringToIndex(index) == "!" {
InputName.removeAtIndex(index)
}
}
have this error " fatal error: subscript: subRange extends past String end ", how should I do? THX :D
Swift 5+
let myString = "aaaaaaaabbbb"
let replaced = myString.replacingOccurrences(of: "bbbb", with: "") // "aaaaaaaa"
If you need to remove characters only on both ends, you can use stringByTrimmingCharactersInSet(_:)
let delCharSet = NSCharacterSet(charactersInString: "! ")
let s1 = "! aString! !"
let s1Del = s1.stringByTrimmingCharactersInSet(delCharSet)
print(s1Del) //->aString
let s2 = "! anotherString !! aString! !"
let s2Del = s2.stringByTrimmingCharactersInSet(delCharSet)
print(s2Del) //->anotherString !! aString
If you need to remove characters also in the middle, "reconstruct from the filtered output" would be a little bit more efficient than repeating single character removal.
var tempUSView = String.UnicodeScalarView()
tempUSView.appendContentsOf(s2.unicodeScalars.lazy.filter{!delCharSet.longCharacterIsMember($0.value)})
let s2DelAll = String(tempUSView)
print(s2DelAll) //->anotherStringaString
If you don't mind generating many intermediate Strings and Arrays, this single liner can generate the expected output:
let s2DelAll2 = s2.componentsSeparatedByCharactersInSet(delCharSet).joinWithSeparator("")
print(s2DelAll2) //->anotherStringaString
I find that the filter method is a good way to go for this sort of thing:
let unfiltered = "! !! yuahl! !"
// Array of Characters to remove
let removal: [Character] = ["!"," "]
// turn the string into an Array
let unfilteredCharacters = unfiltered.characters
// return an Array without the removal Characters
let filteredCharacters = unfilteredCharacters.filter { !removal.contains($0) }
// build a String with the filtered Array
let filtered = String(filteredCharacters)
print(filtered) // => "yeah"
// combined to a single line
print(String(unfiltered.characters.filter { !removal.contains($0) })) // => "yuahl"
Swift 3
In Swift 3, the syntax is a bit nicer. As a result of the Great Swiftification of the old APIs, the factory method is now called trimmingCharacters(in:). Also, you can construct the CharacterSet as a Set of single-character Strings:
let string = "! !! yuahl! !"
string.trimmingCharacters(in: [" ", "!"]) // "yuahl"
If you have characters in the middle of the string you would like to remove as well, you can use components(separatedBy:).joined():
let string = "! !! yu !ahl! !"
string.components(separatedBy: ["!", " "]).joined() // "yuahl"
H/T #OOPer for the Swift 2 version
func trimLast(character chars: Set<Character>) -> String {
let str: String = String(self.reversed())
guard let index = str.index(where: {!chars.contains($0)}) else {
return self
}
return String((str[index..<str.endIndex]).reversed())
}
Note:
By adding this function in String extension, you can delete the specific character of string at last.
for index in InputName.characters.indices.reversed() {
if String(InputName[index]) == "" || InputName.substringToIndex(index) == "!" {
InputName.removeAtIndex(index)
}
}
Also you can add such very helpful extension :
import Foundation
extension String{
func exclude(find:String) -> String {
return stringByReplacingOccurrencesOfString(find, withString: "", options: .CaseInsensitiveSearch, range: nil)
}
func replaceAll(find:String, with:String) -> String {
return stringByReplacingOccurrencesOfString(find, withString: with, options: .CaseInsensitiveSearch, range: nil)
}
}
you can use this:
for example if you want to remove "%" the percent from 10%
if let i = text.firstIndex(of: "%") {
text.remove(at: i) //10
}