I am trying to write a program that takes a number input from user and stores it into a string, then i am trying to convert that string to integer for further use. Whenever i convert it, it displays nil for the integer value but will print the input when kept as a string. Here is my code so far. This is my first time trying to write in swift.
import Foundation
func input() -> String{
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding) as! String
}
print("What is a number: ")
let user: String? = input()
print("You typed: " + user!)
var num = Int(user!)
print("Your number was" ,(num))
The Int function returns an optional integer, so if your string can't be converted it will return nil. If you assign it a value that it can convert, you'll get the result you're looking for:
let user: String = "5"
var num = Int(user)
if let num = num {
print("Your number was \(num)")
} else {
print("Your number is nil")
}
Also, your input function is returning a String, but you're defining the user variable as an optional String?
After searching around and trying different things, I was able to do exactly what I wanted after doing...
var user = input()
var newString = user.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet())
Related
I have to create a function that removes duplicate characters from a string. There are many questions regarding this same topic, but the difference is that when removing the string, it has to evaluate if the character is equal to the one before it. For example: if the string is "teeth", the output must be "teth". The code I have now:
def remove_duplicates(s):
result = ""
for char in s:
if char :
"".join(result)
print(char)
return result
If anyone can help, it would be appreciated.
def remove_duplicates(s):
result = ""
per_char = None
for char in s:
if per_char != char:
result += char
per_char = char
return result
I want convert string to Map in grails. I already have a function of string to map conversion. Heres the code,
static def StringToMap(String reportValues){
Map result=[:]
result=reportValues.replace('[','').replace(']','').replace(' ','').split(',').inject([:]){map,token ->
List tokenizeStr=token.split(':');
tokenizeStr.size()>1?tokenizeStr?.with {map[it[0]?.toString()?.trim()]=it[1]?.toString()?.trim()}:tokenizeStr?.with {map[it[0]?.toString()?.trim()]=''}
map
}
return result
}
But, I have String with comma in the values, so the above function doesn't work for me. Heres my String
[program_type:, subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC, INC]
my function returns ABC only. not ABC, INC. I googled about it but couldnt find any concrete help.
Generally speaking, if I have to convert a Stringified Map to a Map object I try to make use of Eval.me. Your example String though isn't quite right to do so, if you had the following it would "just work":
// Note I have added '' around the values.
String a = "[program_type:'', subsidiary_code:'', groupName:'', termination_date:'', effective_date:'', subsidiary_name:'ABC']"
Map b = Eval.me(a)
// returns b = [program_type:, subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC]
If you have control of the String then if you can create it following this kind of pattern, it would be the easiest solution I suspect.
In case it is not possible to change the input parameter, this might be a not so clean and not so short option. It relies on the colon instead of comma values.
String reportValues = "[program_type:, subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC, INC]"
reportValues = reportValues[1..-2]
def m = reportValues.split(":")
def map = [:]
def length = m.size()
m.eachWithIndex { v, i ->
if(i != 0) {
List l = m[i].split(",")
if (i == length-1) {
map.put(m[i-1].split(",")[-1], l.join(","))
} else {
map.put(m[i-1].split(",")[-1], l[0..-2].join(","))
}
}
}
map.each {key, value -> println "key: " + key + " value: " + value}
BTW: Only use eval on trusted input, AFAIK it executes everything.
You could try messing around with this bit of code:
String tempString = "[program_type:11, 'aa':'bb', subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC, INC]"
List StringasList = tempString.tokenize('[],')
def finalMap=[:]
StringasList?.each { e->
def f = e?.split(':')
finalMap."${f[0]}"= f.size()>1 ? f[1] : null
}
println """-- tempString: ${tempString.getClass()} StringasList: ${StringasList.getClass()}
finalMap: ${finalMap.getClass()} \n Results\n finalMap ${finalMap}
"""
Above produces:
-- tempString: class java.lang.String StringasList: class java.util.ArrayList
finalMap: class java.util.LinkedHashMap
Results
finalMap [program_type:11, 'aa':'bb', subsidiary_code:null, groupName:null, termination_date:null, effective_date:null, subsidiary_name:ABC, INC:null]
It tokenizes the String then converts ArrayList by iterating through the list and passing each one again split against : into a map. It also has to check to ensure the size is greater than 1 otherwise it will break on f[1]
I'm having trouble converting a String to Int in my Swift OS X Xcode project. I have some data saved in a text file in a comma delimited format. The contents of the text file is below:
1,Cessna 172,3,54.4,124,38.6112
(and a line break at the end)
I read the text file and seperate it, first by \n to get each line by itself, and then by , to get each element by itself. The code to do this is below:
if let dir : NSString = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true).first {
let path = dir.stringByAppendingPathComponent("FSPassengers/aircraft.txt")
do {
let content = try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding)
if content != "" {
let astrContent:[String] = content.componentsSeparatedByString("\n")
for aeroplane in astrContent {
let aSeperated:[String] = aeroplane.componentsSeparatedByString(",")
print(aSeperated[0])
print(Int(aSeperated[0]))
//self.aAircraft.append(Aircraft(id: aSeperated[0], type: aSeperated[1], passengerCapacity: Int(aSeperated[2])!, cargoCapacityKg: Double(aSeperated[3])!, cruiseSpeed: Int(aSeperated[4])!, fuelLitresPerHour: Double(aSeperated[5])!))
}
}
}
catch {
print("Error")
}
}
The end result here will be to assign each record (each line of the text file) into the array aAircraft. This array is made up of a custom object called Aircraft. The custom class is below:
class Aircraft: NSObject {
var id:Int = Int()
var type:String = String()
var passengerCapacity:Int = Int()
var cargoCapacityKg:Double = Double()
var cruiseSpeed:Int = Int()
var fuelLitresPerHour:Double = Double()
override init() {}
init(id:Int, type:String, passengerCapacity:Int, cargoCapacityKg:Double, cruiseSpeed:Int, fuelLitresPerHour:Double) {
self.id = id
self.type = type
self.passengerCapacity = passengerCapacity
self.cargoCapacityKg = cargoCapacityKg
self.cruiseSpeed = cruiseSpeed
self.fuelLitresPerHour = fuelLitresPerHour
}
}
In the first code extract above, where I split the text file contents and attempt to assign them into the array, you will see that I have commented out the append line. I have done this to get the application to compile, at the moment it is throwing me errors.
The error revolves around the conversion of the String values to Int and Double values as required. For example, Aircraft.id, or aSeperated[0] needs to be an Int. You can see that I use the line Int(aSeperated[0]) to convert the String to Int in order to assign it into the custom object. However, this line of code is failing.
The two print statements in the first code extract output the following values:
1
Optional(1)
If I add a ! to the end of the second print statement to make them:
print(aSeperated[0])
print(Int(aSeperated[0])!)
I get the following output:
I understand what the error means, that it tried to unwrap an optional value because I force unwrapped it, and it couldn't find an Int value within the string I passed to it, but I don't understand why I am getting the error. The string value is 1, which is very clearly an integer. What am I doing wrong?
Because Casena 172 is not convertible to an Int. You also have other decimal numbers which you will lose precision when casting them to Int. Use NSScanner to create an initializer from a CSV string:
init(csvString: String) {
let scanner = NSScanner(string: csvString)
var type: NSString?
scanner.scanInteger(&self.id)
scanner.scanLocation += 1
scanner.scanUpToString(",", intoString: &type)
self.type = type as! String
scanner.scanLocation += 1
scanner.scanInteger(&self.passengerCapacity)
scanner.scanLocation += 1
scanner.scanDouble(&self.cargoCapacityKg)
scanner.scanLocation += 1
scanner.scanInteger(&self.cruiseSpeed)
scanner.scanLocation += 1
scanner.scanDouble(&self.fuelLitresPerHour)
}
Usage:
let aircraft = Aircraft(csvString: "1,Cessna 172,3,54.4,124,38.6112")
As #mrkxbt mentioned, the issue was related to the blank line after the data in the text file. The string was being split at the \n which was assigning two values into the array. The first value was a string containing the data and the second was an empty string, so obviously the second set of splitting (by ,) was failing. Amended and working code is below:
if let dir : NSString = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true).first {
let path = dir.stringByAppendingPathComponent("FSPassengers/aircraft.txt")
do {
let content = try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding)
if content != "" {
let astrContent:[String] = content.componentsSeparatedByString("\n")
for aeroplane in astrContent {
if aeroplane != "" {
let aSeperated:[String] = aeroplane.componentsSeparatedByString(",")
print(aSeperated[0])
print(Int(aSeperated[0])!)
self.aAircraft.append(Aircraft(id: Int(aSeperated[0])!, type: aSeperated[1], passengerCapacity: Int(aSeperated[2])!, cargoCapacityKg: Double(aSeperated[3])!, cruiseSpeed: Int(aSeperated[4])!, fuelLitresPerHour: Double(aSeperated[5])!))
}
}
}
}
catch {
print("Error")
}
}
A function in swift takes any numeric type in Swift (Int, Double, Float, UInt, etc).
the function converts the number to a string
the function signature is as follows :
func swiftNumbers <T : NumericType> (number : T) -> String {
//body
}
NumericType is a custom protocol that has been added to numeric types in Swift.
inside the body of the function, the number should be converted to a string:
I use the following
var stringFromNumber = "\(number)"
which is not so elegant, PLUS : if the absolute value of the number is strictly inferior to 0.0001 it gives this:
"\(0.000099)" //"9.9e-05"
or if the number is a big number :
"\(999999999999999999.9999)" //"1e+18"
is there a way to work around this string interpolation limitation? (without using Objective-C)
P.S :
NumberFormater doesn't work either
import Foundation
let number : NSNumber = 9_999_999_999_999_997
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 20
formatter.minimumIntegerDigits = 20
formatter.minimumSignificantDigits = 40
formatter.string(from: number) // "9999999999999996.000000000000000000000000"
let stringFromNumber = String(format: "%20.20f", number) // "0.00000000000000000000"
Swift String Interpolation
1) Adding different types to a string
2) Means the string is created from a mix of constants, variables, literals or expressions.
Example:
let length:Float = 3.14
var breadth = 10
var myString = "Area of a rectangle is length*breadth"
myString = "\(myString) i.e. = \(length)*\(breadth)"
Output:
3.14
10
Area of a rectangle is length*breadth
Area of a rectangle is length*breadth i.e. = 3.14*10
Use the Swift String initializer: String(format: <#String#>, arguments: <#[CVarArgType]#>)
For example:
let stringFromNumber = String(format: "%.2f", number)
String and Characters conforms to StringInterpolationProtocol protocol which provide more power to the strings.
StringInterpolationProtocol - "Represents the contents of a string literal with interpolations while it’s being built up."
String interpolation has been around since the earliest days of Swift, but in Swift 5.0 it’s getting a massive overhaul to make it faster and more powerful.
let name = "Ashwinee Dhakde"
print("Hello, I'm \(name)")
Using the new string interpolation system in Swift 5.0 we can extend String.StringInterpolation to add our own custom interpolations, like this:
extension String.StringInterpolation {
mutating func appendInterpolation(_ value: Date) {
let formatter = DateFormatter()
formatter.dateStyle = .full
let dateString = formatter.string(from: value)
appendLiteral(dateString)
}
}
Usage: print("Today's date is \(Date()).")
We can even provide user-defined names to use String-Interpolation, let's understand with an example.
extension String.StringInterpolation {
mutating func appendInterpolation(JSON JSONData: Data) {
guard
let JSONObject = try? JSONSerialization.jsonObject(with: JSONData, options: []),
let jsonData = try? JSONSerialization.data(withJSONObject: JSONObject, options: .prettyPrinted) else {
appendInterpolation("Invalid JSON data")
return
}
appendInterpolation("\n\(String(decoding: jsonData, as: UTF8.self))")
}
}
print("The JSON is \(JSON: jsonData)")
Whenever we want to provide "JSON" in the string interpolation statement, it will print the .prettyPrinted
Isn't it cool!!
How can I define a Dictionary with string key in AS3? and how to do read operation?
for example:
var Dic:Dictionary = new Dictionary();
Dic["Exhausted"] = "He who talks more is sooner exhausted, please keep smiling :)";
String str = str.substring(8,str.length-1); // == str = "Exhausted";
trace('Dic[' + str + '] = ' + Dic[str]);
the output is Dic[Exhausted] = undefined???!!
why?
I think you have a syntax error on this line:
String str = str.substring(8,str.length-1);
If you just use this :
var d:Dictionary = new Dictionary();
d["Exhausted"] = "He who talks more is sooner exhausted, please keep smiling :)";
trace(d["Exhausted"]);
You can see it's all fine.
The problem with var str:String = str.substring(8,str.length-1); is that you define a String named "str": var str:String, but you assign a value which is the result of the substring() method called on str and of cours str does not exist yet when you call substring on it.
Not sure if this makes sense: you define str as the result of applying substring on str.
The actionscript compiler should've complained btw:
expected a definition keyword (such as function) after attribute String, not str.
Just a wild guess, but would you happen to have str defined somewhere else in your code and you just update str again using str before using it ? In which case, you shouldn't redefine, str, you should simply assign a new value.
e.g.
//somewhere else
var str:String = "12345678Exhausted";
//further down
var Dic:Dictionary = new Dictionary();
Dic["Exhausted"] = "He who talks more is sooner exhausted, please keep smiling :)";
str = str.substring(8,str.length); // == str = "Exhausted";
trace('Dic[' + str + '] = ' + Dic[str]);
Also, another syntax error is how you define str:
should be var str:String (as2/as3 syntax), not String str(java/c++/etc. style)