Respostas:
A maneira correta de fazer isso é usar readLine
a Biblioteca padrão do Swift.
Exemplo:
let response = readLine()
Fornecerá um valor opcional contendo o texto inserido.
Eu consegui descobrir sem cair no 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
}
var input = NSString(data: NSFileHandle.fileHandleWithStandardInput().availableData, encoding:NSUTF8StringEncoding)
string.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet())
Na verdade não é tão fácil, você tem que interagir com a API C. Não há alternativa para scanf
. Eu construí um pequeno exemplo:
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);
editar A partir do Swift 2.2, a biblioteca padrão inclui readLine
. Também observarei que o Swift mudou para comentários de documentos em markdown. Deixando minha resposta original para o contexto histórico.
Apenas para completar, aqui está uma implementação do Swift readln
que venho usando. Possui 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 irá gerar um arquivo <project> .swiftdoc e o Xcode irá usá-lo.
///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) }
}
Outra alternativa é vincular libedit para edição de linha apropriada (teclas de seta, etc.) e suporte de histórico opcional. Eu queria isso para um projeto que estou começando e montei um exemplo básico de como configurá-lo .
Uso do 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 <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
Em geral, a função readLine () é usada para verificar a entrada do console. Mas não funcionará em projetos iOS normais até ou a menos que você adicione "ferramenta de linha de comando" .
A melhor maneira de testar, você pode fazer:
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
Aqui está um exemplo simples de obtenção de entrada do usuário em um aplicativo baseado em console: Você pode usar readLine (). Faça a entrada do console para o primeiro número e pressione enter. Depois disso, insira 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)
Juro por Deus ... a solução para este problema absolutamente básico me escapou por ANOS. É TÃO simples ... mas há tantas informações vagas / ruins por aí; espero poder salvar alguém de algumas das tocas de coelho sem fundo em que acabei ...
Então, vamos obter uma "string" de "o usuário" por meio de "o console", por meio de stdin
, vamos ?
[NSString.alloc initWithData:
[NSFileHandle.fileHandleWithStandardInput availableData]
encoding:NSUTF8StringEncoding];
se você quiser SEM a nova linha final, basta adicionar ...
[ ... stringByTrimmingCharactersInSet:
NSCharacterSet.newlineCharacterSet];
Ta Da!
♥ ⱥ ᏪℯⅩ
Muitas respostas desatualizadas para esta pergunta. A partir do Swift 2+, a biblioteca padrão do Swift contém a função readline () . Ele retornará um opcional, mas só será nulo se EOF for atingido, o que não acontecerá ao obter a entrada do teclado para que possa ser desembrulhado à força com segurança nesses cenários. Se o usuário não inserir nada, seu valor (desembrulhado) será uma string vazia. Aqui está uma pequena função de utilidade que usa recursão para alertar o usuário até que pelo menos um caractere tenha sido inserido:
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)")
Observe que o uso de ligação opcional (if let input = readLine ()) para verificar se algo foi inserido como proposto em outras respostas não terá o efeito desejado, pois nunca será nulo e pelo menos "" ao aceitar a entrada do teclado.
Isso não funcionará em um Playground ou em qualquer outro ambiente onde você não tenha acesso ao prompt de comando. Parece haver problemas no REPL da linha de comando também.
Como não havia soluções sofisticadas para esse problema, fiz uma pequena classe para ler e analisar a entrada padrão em Swift. Você pode encontrar 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"
}
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 quiser ler uma string separada por espaço e dividir imediatamente a string em uma matriz, você pode fazer o seguinte:
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 função readLine () é executada no Xcode, o console de depuração espera pela entrada. O resto do código será retomado após a entrada ser feita.
let inputStr = readLine()
if let inputStr = inputStr {
print(inputStr)
}
A resposta mais bem classificada para essa pergunta sugere o uso do método readLine () para obter a entrada 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()!
readLine()
retorna opcional por uma razão, portanto, não é seguro forçar o desempacotamento e realmente não adiciona nada ao exemplo.
Swift 5: se você deseja inserir continuamente a partir do teclado, sem encerrar o programa, como um fluxo de entrada, use as etapas abaixo:
Criar novo projeto do tipo ferramenta de linha comnnad
Adicione o código abaixo no arquivo 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);
Eu testei isso no ObjC, e talvez isso seja útil.
Eu só queria comentar (não tenho representantes suficientes) sobre a implementação do xenadu, porque CChar
no OS X é Int8
, e o Swift não gosta nada quando você adiciona ao array quando getchar()
retorna partes de UTF-8, ou qualquer outra coisa acima de 7 bits.
Estou usando um array de UInt8
, em vez disso, funciona muito bem e String.fromCString
converte UInt8
em UTF-8 muito bem.
Porém foi 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<CChar>(cstr))
}
while true {
if let mystring = readln().str {
println(" > \(mystring)")
}
}
Agora consigo obter entrada de teclado em Swift usando o seguinte:
Em meu arquivo main.swift, declarei uma variável i e atribuí a ela a função GetInt () que defini no Objetivo C. Por meio de um cabeçalho chamado Bridging, onde declarei o protótipo de função para GetInt, pude vincular a 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 <Foundation/Foundation.h>
#import <stdio.h>
#import <stdlib.h>
int GetInt()
{
int i;
scanf("%i", &i);
return i;
}
Em obj.m é possível incluir a saída e entrada padrão c, stdio.h, bem 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 incluir um arquivo rápido real como user.c ou algo parecido.
Espero poder ajudar,
Edit: Não é possível obter a entrada String por meio de C porque aqui estou usando o CInt -> o tipo inteiro de C e não de Swift. Não existe um tipo Swift equivalente para o C char *. Portanto, String não é conversível em string. Mas existem soluções bastante por aqui para obter entrada String.
Raul