Risposte:
Il modo corretto per farlo è usare readLine
dalla Swift Standard Library.
Esempio:
let response = readLine()
Ti darà un valore opzionale contenente il testo inserito.
Sono riuscito a capirlo senza scendere in C:
La mia soluzione è la seguente:
func input() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding)!
}
Le versioni più recenti di Xcode richiedono un typecast esplicito (funziona in Xcode 6.4):
func input() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding)! as String
}
var input = NSString(data: NSFileHandle.fileHandleWithStandardInput().availableData, encoding:NSUTF8StringEncoding)
string.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet())
In realtà non è così facile, devi interagire con l'API C. Non c'è alternativa a scanf
. Ho costruito un piccolo esempio:
main.swift
import Foundation
var output: CInt = 0
getInput(&output)
println(output)
UserInput.c
#include <stdio.h>
void getInput(int *output) {
scanf("%i", output);
}
cliinput-Bridging-Header.h
void getInput(int *output);
modifica A partire da Swift 2.2 la libreria standard includereadLine
. Noterò anche che Swift è passato ai commenti ai documenti markdown. Lasciando la mia risposta originale per il contesto storico.
Solo per completezza, ecco un'implementazione rapida di readln
che ho utilizzato. Ha un parametro opzionale per indicare il numero massimo di byte che si desidera leggere (che può essere o meno la lunghezza della stringa).
Questo dimostra anche l'uso corretto dei commenti swiftdoc: Swift genererà un file <progetto> .swiftdoc e Xcode lo userà.
///reads a line from standard input
///
///:param: max specifies the number of bytes to read
///
///:returns: the string, or nil if an error was encountered trying to read Stdin
public func readln(max:Int = 8192) -> String? {
assert(max > 0, "max must be between 1 and Int.max")
var buf:Array<CChar> = []
var c = getchar()
while c != EOF && c != 10 && buf.count < max {
buf.append(CChar(c))
c = getchar()
}
//always null terminate
buf.append(CChar(0))
return buf.withUnsafeBufferPointer { String.fromCString($0.baseAddress) }
}
Un'altra alternativa è collegare libedit per la corretta modifica della riga (tasti freccia, ecc.) E il supporto della cronologia opzionale. Lo volevo per un progetto che sto iniziando e ho messo insieme un esempio di base per come l'ho impostato .
Utilizzo da swift
let prompt: Prompt = Prompt(argv0: C_ARGV[0])
while (true) {
if let line = prompt.gets() {
print("You typed \(line)")
}
}
Wrapper ObjC per esporre libedit
#import <histedit.h>
char* prompt(EditLine *e) {
return "> ";
}
@implementation Prompt
EditLine* _el;
History* _hist;
HistEvent _ev;
- (instancetype) initWithArgv0:(const char*)argv0 {
if (self = [super init]) {
// Setup the editor
_el = el_init(argv0, stdin, stdout, stderr);
el_set(_el, EL_PROMPT, &prompt);
el_set(_el, EL_EDITOR, "emacs");
// With support for history
_hist = history_init();
history(_hist, &_ev, H_SETSIZE, 800);
el_set(_el, EL_HIST, history, _hist);
}
return self;
}
- (void) dealloc {
if (_hist != NULL) {
history_end(_hist);
_hist = NULL;
}
if (_el != NULL) {
el_end(_el);
_el = NULL;
}
}
- (NSString*) gets {
// line includes the trailing newline
int count;
const char* line = el_gets(_el, &count);
if (count > 0) {
history(_hist, &_ev, H_ENTER, line);
return [NSString stringWithCString:line encoding:NSUTF8StringEncoding];
}
return nil;
}
@end
In generale, la funzione readLine () viene utilizzata per la scansione dell'input dalla console. Ma non funzionerà nel normale progetto iOS fino a quando oa meno che non si aggiunga "strumento da riga di comando" .
Il modo migliore per i test, puoi fare:
import Foundation
print("Please enter some input\n")
if let response = readLine() {
print("output :",response)
} else {
print("Nothing")
}
Please enter some input
Hello, World
output : Hello, World
Program ended with exit code: 0
Ecco un semplice esempio di come ricevere input dall'utente su un'applicazione basata su console: È possibile utilizzare readLine (). Prendi l'input dalla console per il primo numero, quindi premi Invio. Dopodiché, prendi l'input per il secondo numero come mostrato nell'immagine seguente:
func solveMefirst(firstNo: Int , secondNo: Int) -> Int {
return firstNo + secondNo
}
let num1 = readLine()
let num2 = readLine()
var IntNum1 = Int(num1!)
var IntNum2 = Int(num2!)
let sum = solveMefirst(IntNum1!, secondNo: IntNum2!)
print(sum)
Lo giuro su Dio .. la soluzione a questo problema di base mi è sfuggita per ANNI. È COSÌ semplice .. ma ci sono così tante informazioni vaghe / cattive là fuori; spero di poter salvare qualcuno da alcune delle tane di coniglio senza fondo in cui sono finito ...
Allora, consente di ottenere una "stringa" da "l'utente" tramite "console", via stdin
, per così ?
[NSString.alloc initWithData:
[NSFileHandle.fileHandleWithStandardInput availableData]
encoding:NSUTF8StringEncoding];
se lo vuoi SENZA la nuova riga finale, aggiungi semplicemente ...
[ ... stringByTrimmingCharactersInSet:
NSCharacterSet.newlineCharacterSet];
Ta Da!
♥ ⱥ ᏪℯⅩ
Molte risposte obsolete a questa domanda. A partire da Swift 2+, la libreria Swift Standard contiene la funzione readline () . Restituirà un Opzionale ma sarà nullo solo se è stato raggiunto EOF, il che non accadrà quando si riceve l'input dalla tastiera, quindi può essere tranquillamente scartato con la forza in quegli scenari. Se l'utente non inserisce nulla, il suo valore (non confezionato) sarà una stringa vuota. Ecco una piccola funzione di utilità che utilizza la ricorsione per richiedere all'utente fino a quando non è stato inserito almeno un carattere:
func prompt(message: String) -> String {
print(message)
let input: String = readLine()!
if input == "" {
return prompt(message: message)
} else {
return input
}
}
let input = prompt(message: "Enter something!")
print("You entered \(input)")
Si noti che l'uso dell'associazione opzionale (se let input = readLine ()) per verificare se è stato inserito qualcosa come proposto in altre risposte non avrà l'effetto desiderato, poiché non sarà mai nullo e almeno "" quando si accetta l'input da tastiera.
Non funzionerà in un parco giochi o in qualsiasi altro ambiente in cui non si ha accesso al prompt dei comandi. Sembra avere problemi anche nella REPL della riga di comando.
Poiché non c'erano soluzioni fantasiose a questo problema, ho creato una piccola classe per leggere e analizzare l'input standard in Swift. Puoi trovarlo qui .
Esempio
Analizzare:
+42 st_ring!
-0.987654321 12345678900
.42
Tu fai:
let stdin = StreamScanner.standardInput
if
let i: Int = stdin.read(),
let s: String = stdin.read(),
let d: Double = stdin.read(),
let i64: Int64 = stdin.read(),
let f: Float = stdin.read()
{
print("\(i) \(s) \(d) \(i64) \(f)") //prints "42 st_ring! -0.987654321 12345678900 0.42"
}
Funziona in xCode v6.2, penso che sia Swift v1.2
func input() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding)! as String
}
Se vuoi leggere una stringa separata da spazi e dividere immediatamente la stringa in un array, puoi farlo:
var arr = readLine()!.characters.split(" ").map(String.init)
per esempio.
print("What is your full name?")
var arr = readLine()!.characters.split(" ").map(String.init)
var firstName = ""
var middleName = ""
var lastName = ""
if arr.count > 0 {
firstName = arr[0]
}
if arr.count > 2 {
middleName = arr[1]
lastName = arr[2]
} else if arr.count > 1 {
lastName = arr[1]
}
print("First Name: \(firstName)")
print("Middle Name: \(middleName)")
print("Last Name: \(lastName)")
Quando la funzione readLine () viene eseguita su Xcode, la console di debug attende l'input. Il resto del codice verrà ripreso al termine dell'input.
let inputStr = readLine()
if let inputStr = inputStr {
print(inputStr)
}
La prima risposta a questa domanda suggerisce di utilizzare il metodo readLine () per ricevere l'input dell'utente dalla riga di comando. Tuttavia, voglio sottolineare che è necessario utilizzare il! quando si chiama questo metodo per restituire una stringa invece di un opzionale:
var response = readLine()!
readLine()
restituisce facoltativo per una ragione, non è quindi sicuro scartare forzatamente e in realtà non aggiunge nulla all'esempio.
Swift 5: se desideri continuamente input dalla tastiera, senza terminare il programma, come un flusso di input, utilizza i passaggi seguenti:
Crea un nuovo progetto di tipo comnnad line tool
Aggiungi sotto il codice nel file main.swift:
var inputArray = [String]()
while let input = readLine() {
guard input != "quit" else {
break
}
inputArray.append(input)
print("You entered: \(input)")
print(inputArray)
print("Enter a word:")
}
var a;
scanf("%s\n", n);
L'ho testato in ObjC e forse sarà utile.
Volevo solo commentare (non ho abbastanza ripetizioni) sull'implementazione di xenadu, perché CChar
in OS X lo è Int8
, ea Swift non piace affatto quando aggiungi all'array quandogetchar()
restituisce parti di UTF-8 o qualsiasi altra cosa sopra i 7 bit.
Sto usando invece un array di UInt8
, e funziona benissimo e String.fromCString
converte il fileUInt8
perfettamente in UTF-8.
Comunque è così che l'ho fatto
func readln() -> (str: String?, hadError: Bool) {
var cstr: [UInt8] = []
var c: Int32 = 0
while c != EOF {
c = getchar()
if (c == 10 || c == 13) || c > 255 { break }
cstr.append(UInt8(c))
}
cstr.append(0)
return String.fromCStringRepairingIllFormedUTF8(UnsafePointer<CChar>(cstr))
}
while true {
if let mystring = readln().str {
println(" > \(mystring)")
}
}
Ora sono stato in grado di ottenere l'input da tastiera in Swift utilizzando quanto segue:
Nel mio file main.swift ho dichiarato una variabile ie le ho assegnato la funzione GetInt () che ho definito in Objective C. Tramite un cosiddetto Bridging Header dove ho dichiarato il prototipo della funzione per GetInt potevo collegarmi a main.swift. Ecco i file:
main.swift:
var i: CInt = GetInt()
println("Your input is \(i) ");
Intestazione ponte:
#include "obj.m"
int GetInt();
obj.m:
#import <Foundation/Foundation.h>
#import <stdio.h>
#import <stdlib.h>
int GetInt()
{
int i;
scanf("%i", &i);
return i;
}
In obj.m è possibile includere l'output e l'input standard c, stdio.h, nonché la libreria standard c stdlib.h che consente di programmare in C in Objective-C, il che significa che non è necessario includere un vero file veloce come user.c o qualcosa del genere.
Spero di poterti aiutare
Modifica: non è possibile ottenere l'input di stringa tramite C perché qui sto usando CInt -> il tipo intero di C e non di Swift. Non esiste un tipo Swift equivalente per il carattere C *. Pertanto String non è convertibile in stringa. Ma ci sono abbastanza soluzioni qui intorno per ottenere l'input di String.
Raul