Je tente d'obtenir l'entrée au clavier pour une application de ligne de commande pour le nouveau langage de programmation Apple Swift.
J'ai scanné les documents en vain.
import Foundation
println("What is your name?")
???
Des idées?
J'ai réussi à comprendre sans tomber dans C:
Ma solution est la suivante:
func input() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding)!
}
Les versions plus récentes de Xcode nécessitent une conversion de type explicite (fonctionne dans Xcode 6.4):
func input() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding)! as String
}
Pour ce faire, utilisez readLine
, à partir de la bibliothèque Swift Standard.
Exemple:
let response = readLine()
Vous donnera une valeur optionnelle contenant le texte saisi.
Ce n'est pas si facile, vous devez interagir avec l'API C. Il n'y a pas d'alternative à scanf
. J'ai construit un petit exemple:
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);
edit A partir de Swift 2.2, la bibliothèque standard inclut readLine
. Je noterai également que Swift est passé aux commentaires de Markdown. Laissant ma réponse originale pour le contexte historique.
Juste pour être complet, voici une implémentation rapide de readln
que j'utilise. Il a un paramètre facultatif pour indiquer le nombre maximum d'octets que vous voulez lire (qui peut être ou non la longueur de la chaîne).
Cela démontre également la bonne utilisation des commentaires de swiftdoc - Swift générera un fichier <projet> .swiftdoc et Xcode l’utilisera.
///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) }
}
En général readLine () Cette fonction est utilisée pour balayer les entrées depuis la console. Mais cela ne fonctionnera pas dans un projet iOS normal tant que vous n'ajouterez pas "outil en ligne de commande".
La meilleure façon de tester, vous pouvez faire:
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
Une autre alternative consiste à lier libedit pour une édition de ligne appropriée (touches de direction, etc.) et un support d’historique optionnel. Je voulais cela pour un projet que je commençais et ai construit un exemple de base pour la façon dont je l’ai mis en place .
Utilisation de Swift
let Prompt: Prompt = Prompt(argv0: C_ARGV[0])
while (true) {
if let line = Prompt.gets() {
print("You typed \(line)")
}
}
ObjC wrapper pour exposer 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
Voici un exemple simple de saisie de l'utilisateur sur une application basée sur la console: Vous pouvez utiliser readLine (). Prenez l’entrée de la console pour le premier numéro puis appuyez sur Entrée. Après cela, saisissez le deuxième numéro comme indiqué dans l'image ci-dessous:
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)
La réponse la mieux classée à cette question suggère d'utiliser la méthode readLine () pour prendre en compte les entrées utilisateur à partir de la ligne de commande. Cependant, je tiens à noter que vous devez utiliser le! opérateur lors de l'appel de cette méthode pour retourner une chaîne au lieu d'un optionnel:
var response = readLine()!
Lorsque la fonction readLine () est exécutée sur Xcode, la console de débogage attend l’entrée. Le reste du code sera repris après la saisie.
let inputStr = readLine()
if let inputStr = inputStr {
print(inputStr)
}
Beaucoup de réponses obsolètes à cette question. À partir de Swift 2+, la bibliothèque standard de Swift contient la fonction readline () . Il renverra un facultatif, mais il sera nul si EOF a été atteint, ce qui ne se produira pas lors de la saisie à partir du clavier, de sorte qu'il peut être déplacé en toute sécurité par la force dans ces scénarios. Si l'utilisateur n'entre rien, sa valeur (non enveloppée) sera une chaîne vide. Voici une petite fonction utilitaire qui utilise la récursivité pour inviter l'utilisateur jusqu'à ce qu'au moins un caractère ait été saisi:
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)")
Notez que l'utilisation de la liaison facultative (si let input = readLine ()) pour vérifier si quelque chose a été entré tel que proposé dans d'autres réponses n'aura pas l'effet souhaité, car elle ne sera jamais nulle et au moins "" lors de l'acceptation de l'entrée au clavier.
Cela ne fonctionnera pas dans un terrain de jeu ou dans tout autre environnement où vous n'avez pas accès à la commande Invite. Il semble également y avoir des problèmes dans la ligne de commande REPL.
Comme il n'y avait pas de solution sophistiquée à ce problème, j'ai créé une petite classe pour lire et analyser l'entrée standard dans Swift. Vous pouvez le trouver ici .
Exemple
Pour analyser:
+42 st_ring!
-0.987654321 12345678900
.42
Tu fais:
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"
}
Cela fonctionne dans xCode v6.2, je pense que c'est Swift v1.2
func input() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding)! as String
}
Je jure devant Dieu… la solution à ce problème {absolument fondamental} m'a échappé pendant des années. C'est SO simple .. mais il y a tellement d'informations vagues/mauvaises; j'espère pouvoir sauver quelqu'un de certains du sans-fond des trous de lapin dans lesquels j'ai fini.
Donc, obtenons une "chaîne" de "l'utilisateur" via "la console", via stdin
, doit-on}?
[NSString.alloc initWithData:
[NSFileHandle.fileHandleWithStandardInput availableData]
encoding:NSUTF8StringEncoding];
si vous le voulez SANS la fin de ligne, il suffit d'ajouter ...
[ ... stringByTrimmingCharactersInSet:
NSCharacterSet.newlineCharacterSet];
Ta Da!
♥ ᏪℯⅩ