Я пытаюсь получить ввод с клавиатуры для приложения командной строки для нового языка программирования Apple Swift.
Я просмотрел документы безрезультатно.
import Foundation
println("What is your name?")
???
Любые идеи?
Я пытаюсь получить ввод с клавиатуры для приложения командной строки для нового языка программирования Apple Swift.
Я просмотрел документы безрезультатно.
import Foundation
println("What is your name?")
???
Любые идеи?
Мне удалось разобраться, не спустившись до C:
Мое решение таково:
func input() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding)
}
Более поздние версии Xcode нуждаются в явном приведении типов (работает в Xcode 6.4):
func input() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding) as! String
}
Правильный способ сделать это - использовать readLine
из стандартной библиотеки Swift.
Пример:
let response = readLine()
Дает вам необязательное значение, содержащее введенный текст.
На самом деле это не так просто, вам нужно взаимодействовать с C API. Альтернативы scanf
нет. Я построил небольшой пример:
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-моста-header.h
void getInput(int *output);
изменить. С Swift 2.2 стандартная библиотека включает readLine
. Я также хотел бы отметить, что Свифт переключился на комментарии к доске комментариев. Оставив свой первоначальный ответ на исторический контекст.
Просто для полноты, вот реализация Swift readln
, которую я использовал. Он имеет необязательный параметр для указания максимального количества байтов, которые вы хотите прочитать (что может быть или не быть длиной строки).
Это также демонстрирует правильное использование комментариев swiftdoc - Swift будет генерировать файл <project> .swiftdoc, и Xcode будет использовать его.
///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) }
}
Другой альтернативой является ссылка libedit для правильного редактирования строки (клавиши со стрелками и т.д.) и дополнительной поддержки истории. Я хотел это для проекта, который я начинаю, и собрал базовый пример того, как я его настроил.
Использование с быстрым
let prompt: Prompt = Prompt(argv0: C_ARGV[0])
while (true) {
if let line = prompt.gets() {
print("You typed \(line)")
}
}
ObjC-оболочка для раскрытия 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
Вот простой пример ввода данных от пользователя на консольном приложении: Вы можете использовать readLine(). Возьмите ввод с консоли для первого номера и нажмите enter. После этого введите ввод для второго номера, как показано на рисунке ниже:
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)
До
*******************.
Коррекция
В общем случае функция readLine() используется для сканирования ввода с консоли. Но он не будет работать в обычном проекте iOS до тех пор, пока вы не добавите "инструмент командной строки" .
Лучший способ тестирования:
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
Клянусь Богом... решение этой совершенно основной проблемы ускользало от меня в течение ЛЕТ. Это SO simple.. но там так много туманной/плохой информации; надеюсь, я смогу спасти кого-нибудь из некоторых бездонных кроличьих отверстий, в которых я оказался...
Итак, давайте получим "строку" от "пользователя" через "консоль", через stdin
, будем ли мы?
[NSString.alloc initWithData:
[NSFileHandle.fileHandleWithStandardInput availableData]
encoding:NSUTF8StringEncoding];
если вы хотите его БЕЗ конечной новой строки, просто добавьте...
[ ... stringByTrimmingCharactersInSet:
NSCharacterSet.newlineCharacterSet];
Ta Da!
♥ ⱥ ᏪℯⅩ
Поскольку не было никаких причудливых решений этой проблемы, я сделал крошечный класс для чтения и анализа стандартного ввода в Swift. Вы можете найти здесь здесь.
Пример
Чтобы проанализировать:
+42 st_ring!
-0.987654321 12345678900
.42
Вы делаете:
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"
}
Это работает в xCode v6.2, я думаю, что Swift v1.2
func input() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding)! as String
}
Если вы хотите прочитать строку, разделенную пробелами, и сразу же разбить строку на массив, вы можете сделать это:
var arr = readLine()!.characters.split(" ").map(String.init)
например.
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)")
Когда функция readLine() запускается на Xcode, консоль отладки ожидает ввода. Остальная часть кода будет возобновлена после завершения ввода.
let inputStr = readLine()
if let inputStr = inputStr {
print(inputStr)
}
Я просто хотел прокомментировать (у меня недостаточно повторений) на реализацию xenadu, потому что CChar
в OS X есть Int8
, а Swift вообще не нравится, когда вы добавляете в массив, когда getchar()
возвращает части UTF-8 или что-либо еще выше 7 бит.
Вместо этого я использую массив UInt8
, и он отлично работает, а String.fromCString
отлично преобразует UInt8
в UTF-8.
Однако так я сделал это
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)")
}
}
Теперь я смог получить ввод клавиатуры в Swift, используя следующее:
В моем файле main.swift я объявил переменную я и назначил ей функцию GetInt(), которую я определил в Objective C. Через так называемый заголовок Bridging Header, где я объявил прототип функции для GetInt, я мог ссылаться на main. скор. Вот файлы:
main.swift:
var i: CInt = GetInt()
println("Your input is \(i) ");
Заголовок заголовка:
#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;
}
В obj.m можно включить стандартный вывод и вход c, stdio.h, а также стандартную библиотеку stdlib.h c, которая позволяет вам программировать на C в Objective-C, что означает, что нет необходимо включить настоящий быстрый файл, такой как user.c или что-то в этом роде.
Надеюсь, что смогу помочь,
Изменить: невозможно получить вход String через C, потому что здесь я использую CInt → целочисленный тип C, а не Swift. Для C char * нет эквивалентного типа Swift. Поэтому String не конвертируется в строку. Но здесь есть довольно много решений, чтобы получить вход String.
Раул