Tiago Ferreira Tiago Ferreira - 6 months ago 7x
Swift Question

Recreating Python's input statement in Swift

I was trying to recreate Python's

statement in Swift, I have seen some examples, but I am trying to make it better, firstly, my version removes the
part of the string, also, I was trying to make it firstly print a prompt, so that
var example = input()
would just wait for the message, (which it does), but then
var example = input("Enter text: ")
would print
Enter text:
and wait for text to be inputed.

The problem is, swift seems to be messing up the print's order. For example, being the code:

import Foundation

func input(inputStatement: String? = nil) -> String {
if let inputStatement = inputStatement {
print(inputStatement, terminator:"")
let keyboard = NSFileHandle.fileHandleWithStandardInput()
let inputData = keyboard.availableData
var strData = NSString(data: inputData, encoding: NSUTF8StringEncoding) as! String
strData = strData.stringByReplacingOccurrencesOfString("\n", withString: "")
return strData

print("Creating the input statement in Swift!")
var test = input("What's your name: ")
print("You entered: \(test).")

And the input text, "hi", this prints:

Creating the input statement in Swift!
What's your name: You entered: hi.

And what I expected was:

Creating the input statement in Swift!
What's your name: hi
You entered: hi.

What am I missing here?



The problem is that the standard output file descriptor is line buffered when writing to a terminal (and fully buffered otherwise). Therefore the output of

print(inputStatement, terminator:"")

is buffered and not written before the


writes a newline. You can fix that by flushing the file descriptor explicitly:

if let inputStatement = inputStatement {
    print(inputStatement, terminator:"")

Note also that there is a

public func readLine(stripNewline stripNewline: Bool = default) -> String?

which reads a line from standard input, with the option to remove the trailing newline character. This function also flushes standard output. Therefore a simpler implementation would be

func input(prompt: String = "") -> String {
    print(prompt, terminator: "")
    guard let reply = readLine(stripNewline: true) else {
        fatalError("Unexpected EOF on input")
    return reply

(Of course you might choose to handle "end of file" differently.)