98 votes

Entrée par le clavier dans une application en ligne de commande

J'essaie d'obtenir la saisie du clavier pour une application en ligne de commande pour le nouveau langage de programmation Swift d'Apple.

J'ai scanné les documents en vain.

import Foundation

println("What is your name?")
???

Des idées ?

63voto

Chalkers Points 511

J'ai réussi à le comprendre sans descendre en 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 un typecast 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
}

6 votes

J'aime bien ça, et on peut aussi le comprimer en une seule ligne si on ne veut pas définir une fonction, par exemple si on n'a besoin d'accepter une entrée qu'une seule fois dans un programme : var input = NSString(data: NSFileHandle.fileHandleWithStandardInput().availableData, encoding:NSUTF8StringEncoding)

3 votes

Existe-t-il un moyen de l'utiliser dans le Playground pour accepter les entrées de l'utilisateur à la volée ?

5 votes

Vous ne pouvez pas l'utiliser dans la cour de récréation. Vous devez y utiliser des variables.

14voto

Leandros Points 5916

En fait, ce n'est pas si simple, 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);

0 votes

Oh là là - j'aimerais qu'il y ait quelque chose de plus banal que ça ! Je trouve qu'il est difficile de s'adapter

7voto

xenadu Points 1669

editar A partir de Swift 2.2, la bibliothèque standard comprend readLine . Je note également que Swift est passé aux commentaires de documents markdown. Je laisse ma réponse originale pour le contexte historique.

Par souci d'exhaustivité, voici une implémentation Swift de readln Je l'ai utilisé. Il a un paramètre optionnel pour indiquer le nombre maximum d'octets que vous voulez lire (qui peut ou non être la longueur de la chaîne).

Cela démontre également la bonne utilisation des commentaires 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) }
}

0 votes

J'aime les commentaires sur swiftdoc, et le modificateur d'accès "public", je n'avais pas vu ce genre de choses dans Swift auparavant, mais le CChar et le C-String semblent être un retour au C et aux jeux de caractères 8 bits, alors que Swift est un texte Unicode... ou les outils de ligne de commande sont-ils tous ASCII ?

2 votes

Je crois que getchar() retourne l'ASCII. Les terminaux Unicode sont une chose entière dans laquelle je ne voulais pas entrer :)

5voto

Neil Points 161

Une autre alternative est de lier libedit pour une édition correcte des lignes (touches fléchées, etc.) et un support optionnel de l'historique. J'en avais besoin pour un projet que je suis en train de démarrer et j'ai créé une exemple de base pour savoir comment 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)")
    }
}

wrapper ObjC 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

0voto

alex gray Points 5089

Je jure devant Dieu la solution à ce problème complètement basique Ce problème m'a échappé pendant des années. C'est Si simple mais il y a tellement d'informations vagues ou mauvaises. quelqu'un de un peu de de l'infini trous de lapin que je me suis retrouvé dans...

Alors, récupérons une "chaîne" de "l'utilisateur" via "la console", via stdin , devons-nous ?

[NSString.alloc initWithData:
[NSFileHandle.fileHandleWithStandardInput availableData]
                          encoding:NSUTF8StringEncoding];

si vous le voulez SANS la nouvelle ligne de queue, ajoutez simplement...

[ ... stringByTrimmingCharactersInSet:
                       NSCharacterSet.newlineCharacterSet];

Ta Da!

4 votes

Swift, l'OP dit Swift.

1 votes

Il a dit osx. Tout se résume à la même chose ! Embrassez votre EbjC intérieur !

2 votes

Il y a des gens qui écrivent en Swift et qui n'apprendront jamais l'Objective C. Il ne s'agit pas de savoir en quoi cela se compile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X