Я пытаюсь получить ввод с клавиатуры для приложения командной строки для нового языка программирования Apple Swift.
Я просмотрел документы безрезультатно.
import Foundation
println("What is your name?")
???
Любые идеи?
Ответы:
Правильный способ сделать это - использовать readLine
стандартную библиотеку Swift.
Пример:
let response = readLine()
Дает вам необязательное значение, содержащее введенный текст.
Мне удалось понять это, не переходя на 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
}
var input = NSString(data: NSFileHandle.fileHandleWithStandardInput().availableData, encoding:NSUTF8StringEncoding)
string.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet())
На самом деле это не так просто, вам нужно взаимодействовать с 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-Bridging-Header.h
void getInput(int *output);
edit Начиная с Swift 2.2 стандартная библиотека включает readLine
. Также отмечу, что Swift переключился на комментарии к документам по уценке. Оставлю свой первоначальный ответ для исторического контекста.
Просто для полноты, вот реализация 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) }
}
Обычно функция 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
Другой альтернативой является привязка libedit для правильного редактирования строк (клавиши со стрелками и т. Д.) И дополнительной поддержки истории. Я хотел это для проекта, который я начинаю, и собрал базовый пример того, как я его настроил .
Использование из swift
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)
Множество устаревших ответов на этот вопрос. Начиная с Swift 2+, стандартная библиотека Swift содержит функцию readline () . Он вернет Optional, но будет равен нулю только в том случае, если был достигнут EOF, чего не произойдет при получении ввода с клавиатуры, поэтому его можно безопасно развернуть принудительно в этих сценариях. Если пользователь ничего не вводит, его (развернутое) значение будет пустой строкой. Вот небольшая служебная функция, которая использует рекурсию, чтобы запрашивать пользователя, пока не будет введен хотя бы один символ:
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)")
Обратите внимание, что использование необязательной привязки (если let input = readLine ()) для проверки того, было ли что-то введено, как было предложено в других ответах, не будет иметь желаемого эффекта, так как оно никогда не будет равно нулю и, по крайней мере, при приеме ввода с клавиатуры.
Это не будет работать на игровой площадке или в любой другой среде, где у вас нет доступа к командной строке. Кажется, есть проблемы и с REPL командной строки.
Клянусь Богом ... решение этой фундаментальной проблемы ускользало от меня ГОДЫ. Это НАСТОЛЬКО просто ... но существует так много расплывчатой / плохой информации; надеюсь , я могу спасти кого - то от некоторых из бездонных дыр кролика , что я оказался в ...
Итак, давайте получим «строку» от «пользователя» через «консоль» stdin
, не так ли ?
[NSString.alloc initWithData:
[NSFileHandle.fileHandleWithStandardInput availableData]
encoding:NSUTF8StringEncoding];
если вы хотите его БЕЗ завершающего символа новой строки, просто добавьте ...
[ ... stringByTrimmingCharactersInSet:
NSCharacterSet.newlineCharacterSet];
Ta Da!
♥ ⱥ ᏪℯⅩ
Swift 5: если вы постоянно хотите вводить данные с клавиатуры, не завершая программу, например поток ввода, выполните следующие действия:
Создать новый проект типа comnnad line tool
Добавьте ниже код в файл 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:")
}
Поскольку у этой проблемы не было необычных решений, я создал крошечный класс для чтения и анализа стандартного ввода в 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)
}
Самый популярный ответ на этот вопрос предполагает использование метода readLine () для ввода пользовательского ввода из командной строки. Однако хочу отметить, что нужно использовать! при вызове этого метода для возврата строки вместо необязательного:
var response = readLine()!
readLine()
по какой-то причине возвращает необязательно, поэтому принудительное развертывание небезопасно и на самом деле ничего не добавляет к примеру.
var a;
scanf("%s\n", n);
Я тестировал это в ObjC, и, возможно, это будет полезно.
Я просто хотел прокомментировать (у меня недостаточно представителей) реализацию 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 я объявил переменную i и назначил ей функцию GetInt (), которую я определил в Objective C. Через так называемый Bridging Header, где я объявил прототип функции для GetInt, я мог ссылаться на main.swift. Вот файлы:
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, а также стандартную библиотеку c stdlib.h, которая позволяет вам программировать на C в Objective-C, что означает, что нет необходимости включать настоящий быстрый файл типа user.c или что-то в этом роде.
Надеюсь, я смогу помочь,
Изменить: невозможно получить ввод String через C, потому что здесь я использую CInt -> целочисленный тип C, а не Swift. Для C char * не существует эквивалентного типа Swift. Следовательно, String не может быть преобразован в строку. Но здесь достаточно решений для ввода String.
Рауль