Я намагаюся отримати введення з клавіатури для програми командного рядка для нової мови програмування 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())
Насправді це не так просто, вам доведеться взаємодіяти з API C. Альтернативи для цього немає 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);
редагувати Станом на 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) }
}
Загалом, функція 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 для належного редагування рядків (клавіші зі стрілками тощо) та додаткової підтримки історії. Я хотів це для проекту, який я починаю, і склав базовий приклад того, як я його створив .
Використання від швидкого
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 () . Він поверне необов’язковий, але це буде нуль, лише якщо буде досягнуто 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)")
Зверніть увагу, що використання необов’язкового прив’язки (якщо дозволено input = readLine ()) для перевірки того, чи було введено щось, як пропонується в інших відповідях, не матиме бажаного ефекту, оскільки воно ніколи не буде нульовим і, принаймні, "" при прийнятті введення з клавіатури.
Це не буде працювати на дитячому майданчику або в будь-якому іншому середовищі, де у вас немає доступу до командного рядка. Здається, що також є проблеми в командному рядку REPL.
Я клянусь Богом .. рішення цієї цілком основної проблеми уникнуло мене РОКІВ. Це настільки просто .. але там стільки розмитої / поганої інформації; сподіваюся, я можу врятувати когось із якоїсь бездонної кролячої нори, в якій я опинився ...
Тож давайте отримаємо "рядок" від "користувача" через "консоль", через 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)
}
Відповідь на це питання з найвищим рейтингом пропонує використовувати метод readLine () для введення даних користувача з командного рядка. Однак я хочу зазначити, що вам потрібно використовувати! при виклику цього методу, щоб повернути рядок замість необов’язкового:
var response = readLine()!
readLine()повертається необов’язково з причини, тому примусове розгортання небезпечно, і насправді нічого не додає до прикладу.
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:")
} 
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 (), яку я визначив у Цілі 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 або щось подібне.
Сподіваюся, я міг допомогти,
Змінити: Неможливо отримати введення рядка через C, оскільки тут я використовую CInt -> цілий тип C, а не Swift. Немає еквівалентного типу Swift для символу C *. Тому рядок не можна конвертувати в рядок. Але тут досить багато рішень, щоб отримати String input.
Рауль