Swift 3 capitalize string - swift

let first = postalText.text?[(postalText.text?.startIndex)!]
let second = postalText.text?[(postalText.text?.index((postalText.text?.startIndex)!, offsetBy: 1))!]
let third = postalText.text?[(postalText.text?.index((postalText.text?.startIndex)!, offsetBy: 2))!]
I'm trying to capitalize the FIRST and THIRD character and then merge all 3 into a new string
but the .uppercase and .capitalized doesn't work .
Also how do i check that the SECOND character is a number ?

.uppercased and .capitalized only work for strings, what you show there are Characters. You can cast a Character as a String and make it capitalized.
let firstCapitalized = String(first!).capitalized
If you want to check if a Character is an int, you can also make it a String, and then check if casting the String as an Int is non-nil:
if Int("\(second!)") != nil {
print("Is Integer")
}
These cases all assume your first, second, and third are all non-nil, and force-unwraps them.
EDIT
I had some free time and was overlooking some old posts on SO, and I realized this answer I posted isn't using the best coding form. First off, force unwrapping anything is always a bad idea (it's a recipe for a crash in the future), so for the first part. Do something like this:
let firstCapitalized = String(first ?? "").capitalized
This at least gives you a back-out in case first == nil then you'll just be stuck with an empty string.
For the second part, I would use optional unwrapping instead of if Int("\(second!)") != nil. I would say the more proper method would be something like this:
if let second = second, let stringConvertedToInteger = Int("\(String(second))") {
print("\(stringConvertedToInteger) is an integer")
} else {
print("Either second is nil, or it cannot be converted to an integer")
}
This will optionally unwrap the character second, and if it has a value, convert it to an integer (should it be one, checked by optional unwrapping). This is the safest way to do it, and will keep you from experiencing any runtime errors.

Related

Fixed length array and a forced unwrapping of the last and the first elements

I have an array with 3 elements and want to take the first one and the last one elements.
let array = ["a", "b", "c"]
let first: String = array.first!
let last: String = array.last!
SwiftLint mark a force unwrap as a warning. Can I avoid a forced unwrapping when asking about the first and the last elements for a well known (defined) arrays?
I don't want to use a default values like in an example below
let first :String = array.first ?? ""
Edit:
Why am I asking about it? Because, I would like to avoid an warnings from the SwiftLint when using a forced unwrapping when asking for a first and a last element of an array which was defined by a literal and has enough elements to be sure that there is the first and the last element.
Edit 2:
I have found a name for what I was looking for. It's called Static-Sized Arrays. Static-Sized Arrays discussion stoped in 2017 and there is no chance to use it.
Try with index:
let first = array[0]
let last = array[array.count - 1]
Why am I asking about it? Because, I would like to avoid an warnings
from the SwiftLint when using a forced unwrapping when asking for a
first and a last element of an array which was defined by a literal
and has enough elements to be sure that there is the first and the
last element.
You can't really avoid to unwrap optional value, so if you only need it for two cases extensions can help here.
extension Collection {
func first() -> Element {
guard let first = self.first else {
fatalError() // or maybe return any kind of default value?
}
return first
}
}
let array = [1, 2]
array.first() // 1
And if it need to be only in one swift file you can place this code in that file and mark extensions with private keyword.
Can I avoid a forced unwrapping when asking about the first and the last elements for a well known (defined) arrays?
No you don't have to worry about it for a fixed array , actually the optional attachment for the properties first and last is designated to avoid crashes for an empty arrays

Is Nil-Coalescing always needed when using firstIndex(of: Character) in Swift?

Excerpt from The Swift Programming Language (Swift 4.2) documentation by Apple.
let greeting = "Hello, world!"
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
The above example works totally fine except after I exclude the Nil-coalescing part of the code.
let beginning = greeting[..<greeting.firstIndex(of: ",")]
By leaving out the ?? greeting.endIndex, Xcode returns an error.
The question is why is it necessary?
Why can't we just use firstIndex() directly to access the substring.
As it may be no index for the supplied character , so following your way the app will crash
func firstIndex(of element: Character) -> String.Index?
The optional return String.Index? solves it , and that's why you need ??
if you don't supply ??
Then you have to force unwrap let beginning = greeting[..<index] here index should be index! which will cause a crash if it's nil
Consider this example.
let greeting = "Hey There!"
let index = greeting.firstIndex(of: ",")
index is of type Index?, so it can be nil. Since the string has no ',', the value of index is nil.
So this code becomes illegal. Since index cannot be an optional value.
let beginning = greeting[..<index]
You can alternatively unwrap it and get the index if it is valid index like this.
guard let indexFound = index else {
print("Character not) found in string"
return
}
let beginning = greeting[..<indexFound]
print("The first occurance of the character is at \(beginning).")
Real world example: (I know it's not good, but it should be enough :x)
Remember the bot captcha's that pop up in websites? The ones that ask
you to identify the number of cars, street signs etc. So there you
click on the boxes which show the requirement. and click 'submit'. But
if there aren't any, you click 'Skip'. So drawing parallels. If you
have a valid index, it returns the valid index, otherwise it return
nil which is not an valid Index, but it is a valid answer to the
question asked. (Is there a ',' inside the string?) The problem here is, the next part. Slicing an array requires you to have a valid Index, so your index currently is an optional which you can change to a valid index by safely unwrapping like my example or having a nil-coalescing check at the time of getting the index.
You should look up optionals in Swift to get a better understanding.

Idiomatic way to unwrap an integer string input

Sorry if this is a basic question, but I am learning Swift and I don’t understand how to unwrap inputs from readLine().
For example, I would expect this
let n: Int = Int(readLine(strippingNewline: true) ?? -1)
to work, but it doesn’t. Nor does replacing the -1 with a "-1" to match types.
let n: Int = Int(readLine(strippingNewline: true) ?? "-1")
What is the “right” way to do this then? Can someone explain exactly what Swift is doing when it unwraps optionals and uses them as arguments for a constructor like Int?
The whole concept of optionals is a bit foreign to me (a Python programmer); in Python you handle invalid input the “ghetto way”, putting out fires only after they happen:
try:
n = int(input())
except ValueError:
n = None
but I assume the paradigm in Swift is different.
There are two optionals at play here.
First, readLine(strippingNewline: true) is optional. It can return nil if there's no input recieved prior to the End of File (EOF) character being received. It must be unwrapped before being passed into Int()
Secondly, Int() is optional, because the String it was given may not be a valid string representation of a number.
Do not use -1 in Swift to represent "no value". This is called a sentinel value, and it's exactly what optionals are invented to prevent. How do you distinguish between a -1 meaning "no/invalid input", and a -1 meaning "the user's input was -1?
Here is how I would write this code:
guard let userInput = readLine(strippingNewline: true) else {
// If we got to here, readLine(strippingNewLine:) returned nil
fatalError("Received EOF before any input was given")
}
// If we got to here, then userInput is not nil
if let n = Int(userInput) {
// If we got to here, then userInput contained a valid
// String representation of an Int
print("The user entered the Int \(n)")
}
else {
// If we got to here, then userInput did not contain a
// valid String representation of an Int.
print("That is not a valid Int.")
}

Why does Swift's enumerateSubstringsInRange callback take an optional string?

We can extract words from a Swift string like this:
s.enumerateSubstringsInRange(s.characters.indices, options: .ByWords) {
(w,_,_,_) in print(w!)
}
but the forced unwrapping is generally a code smell. It is there because the first parameter of the callback is a String? (an optional). I've tried several possible strings in order to force the function to pass nil to the callback (e.g. the empty string, and strings with no word characters) but with no luck!
So I was wondering why the callback takes an optional string. Is there something I overlooked? Is it because a mutable string can be passed in and modified concurrently? If so, then would it be acceptable practice, if I know my original string is a constant (defined with let), to do the forced unwrap?
(The following information is from the response to my question
https://forums.developer.apple.com/thread/28272 in the
Apple Developer Forum.)
You can pass the .SubstringNotRequired option to enumerateSubstringsInRange(), and then the closure will be called with
substring == nil. This option is documented as
NSStringEnumerationSubstringNotRequired
A way to indicate that the block does not need substring, in which
case nil will be passed. This is simply a performance shortcut.
Example:
let str = "Hello, playground"
str.enumerateSubstringsInRange(str.characters.indices,
options: [.ByWords, .SubstringNotRequired]) {
substring, substringRange, _, _ in
print(substring, substringRange)
}
Output:
nil 0..<5
nil 7..<17
I think it is safe to assume that substring != nil if the
.SubstringNotRequired option is not given.

How do I convert a optional NSInteger to a non-optional one?

I need to retrieve a setting (with Swift):
var highScoreNumber: NSInteger = 0
var returnValue: [NSInteger]? = NSUserDefaults.standardUserDefaults().objectForKey("food") as? [NSInteger]
if (returnValue != nil) {
highScoreNumber = returnValue as NSInteger
}
I tried this and other variations of the code and I always get
'NSInteger?' not convertible to 'NSInteger'
This is my first foray into Swift, so
Am I missing something simple in the conversion?
Is there a better way to retrieve an NSInteger from settings?
When converting a nullable value to a non-nullable one, there are many good options to choose from.
But in your case, you have two issues. One is the array you’re fetching from NSUserDefaults is an array of integers, so you need to decide which one you want from that array.
If it’s the first one you want, you can use the first property. You can use optional chaining to get it. And since it’s a high score, you probably want to default to zero if it’s not present.
Here’s that in one line:
let returnValue = NSUserDefaults.standardUserDefaults().objectForKey("food") as? [Int]
let highscore = returnValue?.first ?? 0
Things to note about the above: there’s no need to give the type to the left of the = if the type is unambiguously determined by what lies to the right of the =. And it’s better to prefer Int over NSInteger.
The returnValue?.first says “if returnValue is nil, then nil, else the value of first (which, itself, returns nil if the array is empty).” The ?? says “if the left of ?? is nil, then the value on the right of nil, else the unwrapped value from the left”.
That said – do you really mean to store an array? Or do you really just want to store a single integer in the defaults and then get that out directly?
let highscore = NSUserDefaults.standardUserDefaults().integerForKey("food")
// and elsewhere in your code, when saving
NSUserDefaults.standardUserDefaults().setInteger(highscore, forKey: "food")
(integerForKey already returns a 0 default when not present rather than an optional, so no need for any unwrapping)