Entrada do teclado no aplicativo de linha de comando

Eu estou tentando obter a input do teclado para um aplicativo de linha de comando para a nova linguagem de programação da Apple Swift.

Eu escaneei os documentos sem sucesso.

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

Alguma ideia?

A maneira correta de fazer isso é usar o readLine , da Biblioteca Padrão Swift.

Exemplo:

 let response = readLine() 

Fornecerá um valor opcional contendo o texto typescript.

Eu consegui descobrir isso sem cair em C:

Minha solução é a seguinte:

 func input() -> String { var keyboard = NSFileHandle.fileHandleWithStandardInput() var inputData = keyboard.availableData return NSString(data: inputData, encoding:NSUTF8StringEncoding)! } 

Versões mais recentes do Xcode precisam de um typecast explícito (funciona no Xcode 6.4):

 func input() -> String { var keyboard = NSFileHandle.fileHandleWithStandardInput() var inputData = keyboard.availableData return NSString(data: inputData, encoding:NSUTF8StringEncoding)! as String } 

Na verdade não é tão fácil, você tem que interagir com a API C. Não há alternativa para o scanf . Eu construí um pequeno exemplo:

main.swift

 import Foundation var output: CInt = 0 getInput(&output) println(output) 

UserInput.c

 #include  void getInput(int *output) { scanf("%i", output); } 

cliinput-Bridging-Header.h

 void getInput(int *output); 

editar A partir do Swift 2.2, a biblioteca padrão inclui o readLine . Eu também notarei que o Swift mudou para os comentários do documento. Deixando minha resposta original para o contexto histórico.

Apenas para completar, aqui está uma implementação Swift de readln eu tenho usado. Ele tem um parâmetro opcional para indicar o número máximo de bytes que você deseja ler (que pode ou não ser o comprimento da String).

Isso também demonstra o uso adequado dos comentários do swiftdoc – o Swift gerará um arquivo .swiftdoc e o Xcode o usará.

 ///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 = [] 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) } } 

Outra alternativa é vincular o libedit à edição de linha apropriada (teclas de seta, etc.) e ao suporte a histórico opcional. Eu queria isso para um projeto que estou começando e coloquei um exemplo básico de como eu o configurei .

Uso de swift

 let prompt: Prompt = Prompt(argv0: C_ARGV[0]) while (true) { if let line = prompt.gets() { print("You typed \(line)") } } 

Wrapper ObjC para expor libedit

 #import  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 

Em geral, a function readLine () é usada para varrer a input do console. Mas ele não funcionará no projeto normal do iOS até ou a menos que você adicione “ferramenta de linha de comando” .

A melhor maneira de testar, você pode fazer:

1. Crie um arquivo macOS

insira a descrição da imagem aqui

2. Use a function readLine () para varrer a String opcional do console

  import Foundation print("Please enter some input\n") if let response = readLine() { print("output :",response) } else { print("Nothing") } 

Saída:

 Please enter some input Hello, World output : Hello, World Program ended with exit code: 0 

insira a descrição da imagem aqui

Aqui está um exemplo simples de input do usuário no aplicativo baseado em console: Você pode usar o readLine (). Tome a input do console para o primeiro número e pressione enter. Depois disso, pegue a input para o segundo número, conforme mostrado na imagem abaixo:

 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) 

Saída

A resposta mais bem posicionada a essa pergunta sugere o uso do método readLine () para aceitar a input do usuário a partir da linha de comando. No entanto, quero observar que você precisa usar o! operador ao chamar este método para retornar uma string em vez de um opcional:

 var response = readLine()! 

Como não havia soluções sofisticadas para esse problema, criei uma pequena class para ler e analisar a input padrão no Swift. Você pode encontrá-lo aqui .

Exemplo

Para analisar:

 +42 st_ring! -0.987654321 12345678900 .42 

Você faz:

 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" } 

Juro por Deus … a solução para este problema absolutamente básico me iludiu por ANOS. É tão simples .. mas há muita informação vaga / ruim por aí; Espero que eu possa salvar alguém de alguns dos buracos de coelho sem fundo que acabei em …

Então, vamos pegar uma “string” do “usuário” via “console”, via stdin , vamos ?

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

Se você quiser, sem a nova linha à direita, basta adicionar …

 [ ... stringByTrimmingCharactersInSet: NSCharacterSet.newlineCharacterSet]; 

Ta Da! ♥ ⱥ ᏪℯⅩ

Antes

insira a descrição da imagem aqui

*******************.

Correção

insira a descrição da imagem aqui

Isso funciona no xCode v6.2, acho que é o Swift v1.2

 func input() -> String { var keyboard = NSFileHandle.fileHandleWithStandardInput() var inputData = keyboard.availableData return NSString(data: inputData, encoding:NSUTF8StringEncoding)! as String } 

Se você quiser ler uma string separada por espaços, e imediatamente dividir a string em uma matriz, você pode fazer isso:

var arr = readLine()!.characters.split(" ").map(String.init)

por exemplo.

 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 a function readLine () é executada no Xcode, o console de debugging aguarda a input. O restante do código será retomado após a input ser feita.

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

Eu só queria comentar (eu não tenho reps suficientes) na implementação do xenadu, porque o CChar no OS X é Int8 , e o Swift não gosta de nada quando você adiciona ao array quando getchar() retorna partes do UTF-8, ou qualquer coisa mais acima de 7 bits.

Eu estou usando uma matriz de UInt8 vez disso, e funciona muito bem e String.fromCString converte o UInt8 em UTF-8 muito bem.

No entanto, é assim que eu fiz

 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(cstr)) } while true { if let mystring = readln().str { println(" > \(mystring)") } } 

Agora consegui obter a input do teclado no Swift usando o seguinte:

No meu arquivo main.swift eu declarei uma variável i e atribui a ela a function GetInt () que eu defini no Objective C. Através de um chamado Bridging Header onde eu declarei o protótipo da function para GetInt eu poderia linkar para main.swift. Aqui estão os arquivos:

main.swift:

 var i: CInt = GetInt() println("Your input is \(i) "); 

Cabeçalho de ponte:

 #include "obj.m" int GetInt(); 

obj.m:

 #import  #import  #import  int GetInt() { int i; scanf("%i", &i); return i; } 

Em obj.m é possível include a saída e input padrão c, stdio.h, assim como a biblioteca padrão c stdlib.h que permite programar em C em Objective-C, o que significa que não há necessidade de include um arquivo real rápido como user.c ou algo parecido.

Espero que eu possa ajudar

Edit: Não é possível obter a input String através de C, porque aqui eu estou usando o CInt -> o tipo inteiro de C e não do Swift. Não existe um tipo Swift equivalente para o C char *. Portanto, String não é convertível em string. Mas existem soluções bastante suficientes por aqui para obter a input String.

Raul