String replacement not working with Dictionary - swift

I have a mini dictionary that I would like to use in order to replace occurrences of text within a user's inputted string. However, instead of replacing every occurrence of a particular string, it retains the original string. For example, user types:
"The girl went to school"
My program still returns "The girl went to school". It should come out as "The binguel debbo went to jangirde"
func input() -> String {
let keyboard = NSFileHandle.fileHandleWithStandardInput()
let inputData = keyboard.availableData
return (NSString(data: inputData, encoding:NSUTF8StringEncoding)?.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet()))! as! String
}
var userInput = "" //Declares original user input
var finalSentence:String = "" //Declares a string variable for the final sentence
var newUserString:String
var fulfuldeWords = ["man":"gorko", "woman":"debbo",
"boy":"binguel gorko", "girl": "binguel debbo", "work":"golle",
"school":"jangirde", "water":"ndiyam", "horse":"puccu", "cow":"na'i",
"hat":"hufunere", "house":"wuro", "courage":"cuusal", "camel":"gelodi",
"milk":"kossam"
]
print("Please enter a sentence to be partially translated: ") //Ask user for input
userInput = input()
var theStringArray = userInput.componentsSeparatedByString(" ")
for (englishWord, fulaniWord) in fulfuldeWords {
finalSentence = userInput.stringByReplacingOccurrencesOfString(englishWord, withString: fulaniWord)
}
print(finalSentence)
This is being done in Swift and I don't get why it's not working. Where did I go wrong in my code. Thanks!

You need to perform the function stringByReplacingOccurencesOfString on the same variable to get your desired result. So, in your code, store the result on userInput and print as the output as well.
for (englishWord, fulaniWord) in fulfuldeWords {
userInput = userInput.stringByReplacingOccurrencesOfString(englishWord, withString: fulaniWord)
}
print(userInput)

Related

replacing for loop to map method

I am stuck about this goal.
Learn about the map method, and use it in place of the loop that converts the array of characters to an array of strings in updateUI().
I have read Documentation and topics about map, but still all my tries did not work.
//change loop below to map method
for letter in currentGame.formattedWord {
letters.append(String(letter))
}
let wordWithSpacing = letters.joined(separator: " ")
correctWordLabel.text = wordWithSpacing
scoreLabel.text = "Wins: \(totalWins), Losses: \(totalLosses)"
treeImageView.image = UIImage(named: "Tree \(currentGame.incorrectMovesRemaining)")
Thanks for help
The String documentation tells us:
A string is a series of characters, such as "Swift", that forms a collection.
So, you can use map to convert each of these characters to individual strings:
let string = "Hello, world"
let letters = string.map { (character: Character) -> String in
return String(character)
}
Or, more concisely:
let letters = string.map { String($0) }
I did it. the problem was that I left the var letters as an empty array and tried to add characters to this array. Now I realized that this was wrong.
func updateUI() {
let letters = currentGame.formattedWord
let mappedLetters = letters.map { String($0)}
/* for letter in currentGame.formattedWord {
letters.append(String(letter))
} */
Thanks all!

Get the string up to a specific character

var hello = "hello, how are you?"
var hello2 = "hello, how are you #tom?"
i want to delete every letter behind the # sign.
result should be
var hello2 = "hello, how are you #tom?"
->
hello2.trimmed()
print(hello2.trimmed())
-> "hello, how are you"
Update
As i want to use it to link multiple users and replace the space behind #sign with the correct name, I always need the reference to the latest occurrence of the #sign to replace it.
text3 = "hey i love you #Tom #Marcus #Peter"
Example what the final version should look like
to start off
var text = "hello #tom #mark #mathias"
i want to always get the index of the latest # sign in the text
Expanding on #appzYourLife answer, the following will also trim off the whitespace characters after removing everything after the # symbol.
import Foundation
var str = "hello, how are you #tom"
if str.contains("#") {
let endIndex = str.range(of: "#")!.lowerBound
str = str.substring(to: endIndex).trimmingCharacters(in: .whitespacesAndNewlines)
}
print(str) // Output - "hello, how are you"
UPDATE:
In response to finding the last occurance of the # symbol in the string and removing it, here is how I would approach it:
var str = "hello, how are you #tom #tim?"
if str.contains("#") {
//Reverse the string
var reversedStr = String(str.characters.reversed())
//Find the first (last) occurance of #
let endIndex = reversedStr.range(of: "#")!.upperBound
//Get the string up to and after the # symbol
let newStr = reversedStr.substring(from: endIndex).trimmingCharacters(in: .whitespacesAndNewlines)
//Store the new string over the original
str = String(newStr.characters.reversed())
//str = "hello, how are you #tom"
}
Or looking at #appzYourLife answer use range(of:options:range:locale:) instead of literally reversing the characters
var str = "hello, how are you #tom #tim?"
if str.contains("#") {
//Find the last occurrence of #
let endIndex = str.range(of: "#", options: .backwards, range: nil, locale: nil)!.lowerBound
//Get the string up to and after the # symbol
let newStr = str.substring(from: endIndex).trimmingCharacters(in: .whitespacesAndNewlines)
//Store the new string over the original
str = newStr
//str = "hello, how are you #tom"
}
As an added bonus, here is how I would approach removing every # starting with the last and working forward:
var str = "hello, how are you #tom and #tim?"
if str.contains("#") {
while str.contains("#") {
//Reverse the string
var reversedStr = String(str.characters.reversed())
//Find the first (last) occurance of #
let endIndex = reversedStr.range(of: "#")!.upperBound
//Get the string up to and after the # symbol
let newStr = reversedStr.substring(from: endIndex).trimmingCharacters(in: .whitespacesAndNewlines)
//Store the new string over the original
str = String(newStr.characters.reversed())
}
//after while loop, str = "hello, how are you"
}
let text = "hello, how are you #tom?"
let trimSpot = text.index(of: "#") ?? text.endIndex
let trimmed = text[..<trimSpot]
Since a string is a collection of Character type, it can be accessed as such. The second line finds the index of the # sign and assigns its value to trimSpot, but if it is not there, the endIndex of the string is assigned through the use of the nil coalescing operator
??
The string, or collection of Characters, can be provided a range that will tell it what characters to get. The expression inside of the brackets,
..<trimSpot
is a range from 0 to trimSpot-1. So,
text[..<trimSpot]
returns an instance of type Substring, which points at the original String instance.
You need to find the range of the "#" and then use it to create a substring up to the index before.
import Foundation
let text = "hello, how are you #tom?"
if let range = text.range(of: "#") {
let result = text.substring(to: range.lowerBound)
print(result) // "hello, how are you "
}
Considerations
Please note that, following the logic you described and using the input text you provided, the output string will have a blank space as last character
Also note that if multiple # are presente in the input text, then the first occurrence will be used.
Last index [Update]
I am adding this new section to answer the question you posted in the comments.
If you have a text like this
let text = "hello #tom #mark #mathias"
and you want the index of the last occurrency of "#" you can write
if let index = text.range(of: "#", options: .backwards)?.lowerBound {
print(index)
}
Try regular expressions, they are much safer (if you know what you are doing...)
let hello2 = "hello, how are you #tom, #my #next #victim?"
let deletedStringsAfterAtSign = hello2.replacingOccurrences(of: "#\\w+", with: "", options: .regularExpression, range: nil)
print(deletedStringsAfterAtSign)
//prints "hello, how are you , ?"
And this code removes exactly what you need and leaves the characters after the strings clear, so you can see the , and ? still being there. :)
EDIT: what you asked in comments to this answer:
let hello2 = "hello, how are you #tom, #my #next #victim?"
if let elementIwannaAfterEveryAtSign = hello2.components(separatedBy: " #").last
{
let deletedStringsAfterAtSign = hello2.replacingOccurrences(of: "#\\w+", with: elementIwannaAfterEveryAtSign, options: .regularExpression, range: nil)
print(deletedStringsAfterAtSign)
//prints hello, how are you victim?, victim? victim? victim??
}

Can't compare string entered through terminal to another string in Swift

I am using the following code to implement basic dictionary using swift. However the compiler is not returning any values. I don't know what seems to be the problem. Need Help!
P.S I'm new to Swift.
import Foundation
var dic = ["Nil":"Neel Goswami","Kirana":"Kinara Shah","Sapre":"Rohan Sapre","JP":"Joy Patel","Shreya":"Shrey Bhat","Ali Bhai":"Aalisha Sheth","Gandhi":"Shlok Gandhi","Binti":"Biyanta Shah","Udgam":"Aayushi Shah"]
dic["Wary"] = "Aishwary Rawat"
dic["Sixer"] = "Ruchir Patel"
dic["Bhikhari"] = "Aabhas Singhal"
var str: String? = "Initial"
println("Enter the pet name: ")
str = NSString(data: NSFileHandle.fileHandleWithStandardInput().availableData, encoding:NSUTF8StringEncoding)
var st: String = str!
for (pet, act) in dic
{
if (pet == st) {
println("His/Her actual name is \(act)")
}
}
The problem is that the string from the user input contains a trailing newline character
(\n). You can fix that by changing
var st: String = str!
to
var st = str!.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet())
Alternatively, use
var st = str!.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
which removes leading and trailing space characters as well.
Note that you could simplify your for-loop to a dictionary lookup:
if let act = dic[st] {
println("His/Her actual name is \(act)")
}

Swift, Tuples issue #2

Sorry about the last thread where I posted this question by accident! Here it is. I received a response from someone (Their response is at bottom of page) and unfortunately it did not work. Thanks in advance!
Create a variable named result and assign it the tuple returned from function greeting. (Note: pass the string "Tom" to the greeting function.)
func greeting() -> (language: String, greeting: String, name: String) {
let language = "English"
let greeting = "Hello"
let name = "Tom"
return (language, greeting, name)
}
var result = greeting()
Error = Your function needs to return a tuple with elements named 'greeting' and 'language'.
Now this solution below tells me that my variable has the wrong value in it, but I can't figure out how to pass it "Tom" to the greeting function because I keep getting an error.
func greeting() -> (language: String, greeting: String) {
let language = "English"
let greeting = "Hello"
return (language, greeting)
}
var result = greeting("Tom")
Response I got in the last thread is below. I still get the error message saying that I need to assign the return value of greeting to result.
func greeting(name:String) -> (language: String, greeting: String) {
let language = "English"
let greeting = "Hello " + name + "!"
return (language, greeting)
}
var result = greeting("Tom").greeting
The task is
Create a variable named result and assign it the tuple returned from function greeting.
What you do in the last block is
var result = greeting("Tom").greeting
what I would expect you to do is
var result = greeting("Tom")

Interpolate String Loaded From File

I can't figure out how to load a string from a file and have variables referenced in that string be interpolated.
Let's say a text file at filePath that has these contents:
Hello there, \(name)!
I can load this file into a string with:
let string = String.stringWithContentsOfFile(filePath, encoding: NSUTF8StringEncoding, error: nil)!
In my class, I have loaded a name in: let name = "George"
I'd like this new string to interpolate the \(name) using my constant, so that its value is Hello there, George!. (In reality the text file is a much larger template with lots of strings that need to be swapped in.)
I see String has a convertFromStringInterpolation method but I can't figure out if that's the right way to do this. Does anyone have any ideas?
This cannot be done as you intend, because it goes against type safety at compile time (the compiler cannot check type safety on the variables that you are trying to refer to on the string file).
As a workaround, you can manually define a replacement table, as follows:
// Extend String to conform to the Printable protocol
extension String: Printable
{
public var description: String { return self }
}
var string = "Hello there, [firstName] [lastName]. You are [height]cm tall and [age] years old!"
let firstName = "John"
let lastName = "Appleseed"
let age = 33
let height = 1.74
let tokenTable: [String: Printable] = [
"[firstName]": firstName,
"[lastName]": lastName,
"[age]": age,
"[height]": height]
for (token, value) in tokenTable
{
string = string.stringByReplacingOccurrencesOfString(token, withString: value.description)
}
println(string)
// Prints: "Hello there, John Appleseed. You are 1.74cm tall and 33 years old!"
You can store entities of any type as the values of tokenTable, as long as they conform to the Printable protocol.
To automate things further, you could define the tokenTable constant in a separate Swift file, and auto-generate that file by using a separate script to extract the tokens from your string-containing file.
Note that this approach will probably be quite inefficient with very large string files (but not much more inefficient than reading the whole string into memory on the first place). If that is a problem, consider processing the string file in a buffered way.
There is no built in mechanism for doing this, you will have to create your own.
Here is an example of a VERY rudimentary version:
var values = [
"name": "George"
]
var textFromFile = "Hello there, <name>!"
var parts = split(textFromFile, {$0 == "<" || $0 == ">"}, maxSplit: 10, allowEmptySlices: true)
var output = ""
for index in 0 ..< parts.count {
if index % 2 == 0 {
// If it is even, it is not a variable
output += parts[index]
}
else {
// If it is odd, it is a variable so look it up
if let value = values[parts[index]] {
output += value
}
else {
output += "NOT_FOUND"
}
}
}
println(output) // "Hello there, George!"
Depending on your use case, you will probably have to make this much more robust.