Input numbers only

Hi everyone!! I created an algorithm that doesn't accept any characters from a user, but numbers. I am aware of overflowing.

The question: The algorithm doesn't seem to be compact and efficient. How can I make it more readable, compact, and effective( in terms of memory )? Thank you in advance.

The algorithm is as follows:

var inPut : String
var noLetters : Bool! = nil
var onlyNumbers : [Character] = ["1","2","3","4","5","6","7","8","9","0"]
repeat {
    print("Enter a number.")
    inPut = readLine()!
    for character in inPut {
        if onlyNumbers.contains(character) || character == "-"
        {
            noLetters = true
            continue
        }
        if onlyNumbers.contains(character) != true
        { print("Sorry, numbers only.")
         noLetters = false
            break
        }
    }
}while noLetters == false
print(Int(inPut)!)

Couple of things:

1). You need to test for "-" (and "+" for that matter) only on the first character. The way you have it, "12-34" will pass your tests, and +123 will not.

2). You could re-cast it like so:

...
inPut = readLine()
var noLetters : Bool
repeat {
    noLetters = true
    for character in inPut {
        guard legalCharacter(character)  else {
            print("Sorry, numbers only.")
            noLetters = false
            break;
        }
    }
} while ! noLetters
...

where legalCharacter is a hypothetical function that tests for legality, taking into account a leading '-' or '+' and flagging as illegal if '-' or '+' is found in middle or end of string.

1 Like

I came up with a new simple way. Perhaps, some beginners might need it. This way lets me avoid repetition, overflowing, and misleading with negative as well as positive numbers' signs in the middle of a number entered.

var noCharacters: Bool = true

var numberOnly: Int

repeat {

print("Enter the second number")

numberOnly = Int(readLine() ?? "-1") ?? -1

if numberOnly == -1 {

print("Sorry you have dialed the wrong number.\nTry again.")

noCharacters = false

}

else {

noCharacters = true

}

}

while noCharacters != true

print("You have entered \(numberOnly)")

You can avoid using -1 as a flag for wrongness by simply checking for nilness. If both readLine() is nil and Int applied to it is nil, you can ask the user to retype the number. You can also avoid the noCharacters flag:

print("Enter an integer")
while true {
  if let line = readLine(), let integer = Int(line) {
    print("You have entered \(integer)")
    break
  } else {
    print("That's not an integer.\nTry again.")
  }
}

The if let statement lets you do two things at once: check if the variable is not nil and, if that's the case, declare a new variable storing its unwrapped value.

if let line = readLine() {
  print(line)
}

// equivalent to:
let optionalLine = readLine()
if optionalLine != nil {
  let line = optionalLine!
  print(line)
}

I highly suggest reading the Swift Programming Language Guide in its entirety :slight_smile:

2 Likes

as a general rule, for any language, not just Swift, choosing a value within your range of discourse (in your case, "-1" in the set of integers) as a flag leads to the question: What if the user wanted to enter a "-1"?. You then have to handle the case. Trapping on "nil" from readline() as suggested addresses that problem.

1 Like

I got it, Thanks. I'm reading, that's helpful.

2 Likes

Yeah, In a week of studying, I realize the code is garbage. This is a note for myself.
The updated version is below.
At least I feel progress daily.

   var input: String?
var acceptedNumbers = "1234567890"
var noChar: Bool = false
repeat
{
    input = readLine()
    for character in input!
    {
        if acceptedNumbers.contains(character){
            noChar = true
            continue
        }
        else
        {
            print("You have dialed the wrong number.Try again!")
            noChar = false
            break
        }
    }
}
while noChar == false
1 Like

You might consider using allSatisfy:

let digits = Set("0123456789")

while let input = readLine() {
  let isValid = input.allSatisfy { char in
    digits.contains(char)
  }
  
  if isValid && !input.isEmpty {
    print("You entered \(input)")
    break
  } else {
    print("Invalid input")
  }
}
1 Like

Why did you use a Set instead of an Array?

To have O(1) lookups for contains.

With a collection that small it doesn’t really matter though.

Got it, I was wondering whether there was any difference.Appreciate it.