Вход с клавиатуры в приложении командной строки

Я пытаюсь получить ввод с клавиатуры для приложения командной строки для нового языка программирования Apple Swift.

Я просмотрел документы безрезультатно.

import Foundation

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

Любые идеи?

Ответ 1

Мне удалось разобраться, не спустившись до 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
}

Ответ 2

Правильный способ сделать это - использовать readLine из стандартной библиотеки Swift.

Пример:

let response = readLine()

Дает вам необязательное значение, содержащее введенный текст.

Ответ 3

На самом деле это не так просто, вам нужно взаимодействовать с 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);

Ответ 4

изменить. С 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) }
}

Ответ 5

Другой альтернативой является ссылка 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

Ответ 6

Вот простой пример ввода данных от пользователя на консольном приложении: Вы можете использовать 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)

Вывод

Ответ 7

До

введите описание изображения здесь

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

Коррекция

введите описание изображения здесь

Ответ 8

В общем случае функция readLine() используется для сканирования ввода с консоли. Но он не будет работать в обычном проекте iOS до тех пор, пока вы не добавите "инструмент командной строки" .

Лучший способ тестирования:

1. Создайте файл macOS

введите описание изображения здесь

2. Используйте функцию readLine() для сканирования необязательной строки из консоли

 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

введите описание изображения здесь

Ответ 9

Клянусь Богом... решение этой совершенно основной проблемы ускользало от меня в течение ЛЕТ. Это SO simple.. но там так много туманной/плохой информации; надеюсь, я смогу спасти кого-нибудь из некоторых бездонных кроличьих отверстий, в которых я оказался...

Итак, давайте получим "строку" от "пользователя" через "консоль", через stdin, будем ли мы?

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

если вы хотите его БЕЗ конечной новой строки, просто добавьте...

[ ... stringByTrimmingCharactersInSet:
                       NSCharacterSet.newlineCharacterSet];

Ta Da! ♥ ⱥ ᏪℯⅩ

Ответ 10

Поскольку не было никаких причудливых решений этой проблемы, я сделал крошечный класс для чтения и анализа стандартного ввода в 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"
}

Ответ 11

Это работает в 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
}

Ответ 12

Если вы хотите прочитать строку, разделенную пробелами, и сразу же разбить строку на массив, вы можете сделать это:

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

Ответ 13

Когда функция readLine() запускается на Xcode, консоль отладки ожидает ввода. Остальная часть кода будет возобновлена ​​после завершения ввода.

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

Ответ 14

Я просто хотел прокомментировать (у меня недостаточно повторений) на реализацию 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)")
    }
}

Ответ 15

Теперь я смог получить ввод клавиатуры в 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.

Раул