Masukan dari keyboard dalam aplikasi baris perintah

94

Saya mencoba mendapatkan input keyboard untuk aplikasi baris perintah untuk bahasa pemrograman Apple yang baru, Swift.

Saya telah memindai dokumen tetapi tidak berhasil.

import Foundation

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

Ada ide?

Kapur
sumber

Jawaban:

138

Cara yang benar untuk melakukannya adalah dengan menggunakan readLine, dari Perpustakaan Standar Swift.

Contoh:

let response = readLine()

Akan memberi Anda nilai Opsional yang berisi teks yang dimasukkan.

Ezekiel Elin
sumber
2
Terima kasih. apakah ada cara untuk mendapatkan jenis masukan kata sandi?
Abhijit Gaikwad
Bagi saya, itu hanya turun melalui baris ini dengan respons = nihil. Tahu apa masalahnya?
Peter Webb
4
@PeterWebb - berfungsi dengan baik di terminal xcode, jatuh di taman bermain :)
aprofromindia
2
readLine ditambahkan setelah sebagian besar jawaban asli, jadi sikapnya agak tidak beralasan IMHO
russbishop
2
Dikoreksi untuk Swift 3, SlimJim
Ezekiel Elin
62

Saya berhasil mengetahuinya tanpa jatuh ke C:

Solusi saya adalah sebagai berikut:

func input() -> String {
    var keyboard = NSFileHandle.fileHandleWithStandardInput()
    var inputData = keyboard.availableData
    return NSString(data: inputData, encoding:NSUTF8StringEncoding)!
}

Versi Xcode yang lebih baru memerlukan typecast eksplisit (berfungsi di Xcode 6.4):

func input() -> String {
    var keyboard = NSFileHandle.fileHandleWithStandardInput()
    var inputData = keyboard.availableData
    return NSString(data: inputData, encoding:NSUTF8StringEncoding)! as String
}
Kapur
sumber
5
Saya suka ini, juga, dapat dikompresi menjadi satu baris jika Anda tidak ingin mendefinisikan suatu fungsi, seperti jika Anda hanya perlu menerima input sekali dalam sebuah program:var input = NSString(data: NSFileHandle.fileHandleWithStandardInput().availableData, encoding:NSUTF8StringEncoding)
jcmiller11
3
Apakah ada cara untuk menggunakan ini di Playground untuk menerima masukan pengguna dengan cepat?
Rob Cameron
5
Anda tidak dapat menggunakan ini di taman bermain. Anda harus menggunakan variabel di sana.
Chalkers
8
Perhatikan bahwa Anda akan mendapatkan baris baru dalam string dengan ini. Hapus mereka denganstring.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet())
pk-nb
3
Anda juga akan mendapatkan karakter aneh jika pengguna menghapus karakter, menggunakan tombol panah, dll. AAAGGGGGHHHH MENGAPA, Swift, Mengapa?
ybakos
14

Sebenarnya tidak semudah itu, Anda harus berinteraksi dengan C API. Tidak ada alternatif untuk scanf. Saya telah membuat sedikit contoh:

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);
Leandros
sumber
Ya ampun - Saya berharap ada sesuatu yang lebih sepele dari ini! Saya merasa sulit untuk mengadaptasi ini untuk serangkaian karakter.
Chalkers
1
Akan lebih baik untuk membuat "UserInput.h" untuk menyimpan definisi fungsi, dan menyertakan file ini di "cliinput-Bridging-Header.h".
Alan Zhiliang Feng
7

sunting Pada Swift 2.2 termasuk pustaka standar readLine. Saya juga akan mencatat Swift beralih ke komentar dokumen penurunan harga. Meninggalkan jawaban asli saya untuk konteks sejarah.

Sekadar kelengkapan, berikut adalah implementasi Swift yang readlntelah saya gunakan. Ini memiliki parameter opsional untuk menunjukkan jumlah maksimum byte yang ingin Anda baca (yang mungkin atau mungkin bukan panjang String).

Ini juga mendemonstrasikan penggunaan yang tepat dari komentar swiftdoc - Swift akan menghasilkan file <project> .swiftdoc dan Xcode akan menggunakannya.

///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) }
}
russbishop.dll
sumber
Saya suka komentar swiftdoc, dan pengubah akses "publik", saya belum pernah melihat hal semacam itu di Swift sebelumnya, tetapi CChar dan C-String tampaknya merupakan kemunduran ke set karakter C dan 8-bit dan Swift semua tentang teks Unicode ... atau apakah semua alat baris perintah ASCII ??
Kaydell
2
Saya yakin getchar () mengembalikan ASCII. Terminal Unicode adalah hal yang tidak ingin saya masuki :)
russbishop
7

Secara umum, fungsi readLine () digunakan untuk memindai input dari konsol. Tapi itu tidak akan bekerja dalam proyek iOS normal sampai atau kecuali Anda menambahkan "alat baris perintah" .

Cara terbaik untuk pengujian, Anda dapat melakukan:

1. Buat file macOS

masukkan deskripsi gambar di sini

2. Gunakan fungsi readLine () untuk memindai String opsional dari konsol

 import Foundation

 print("Please enter some input\n")

 if let response = readLine() {
    print("output :",response)
 } else {
    print("Nothing")
 }

Keluaran:

Please enter some input

Hello, World
output : Hello, World
Program ended with exit code: 0

masukkan deskripsi gambar di sini

Ashis Laha
sumber
5

Alternatif lain adalah menautkan libedit untuk pengeditan baris yang tepat (tombol panah, dll.) Dan dukungan riwayat opsional. Saya menginginkan ini untuk proyek yang saya mulai dan mengumpulkan contoh dasar bagaimana saya mengaturnya .

Penggunaan dari swift

let prompt: Prompt = Prompt(argv0: C_ARGV[0])

while (true) {
    if let line = prompt.gets() {
        print("You typed \(line)")
    }
}

Pembungkus ObjC untuk mengekspos 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
Neil
sumber
3

Berikut adalah contoh sederhana untuk mengambil input dari pengguna pada aplikasi berbasis konsol: Anda dapat menggunakan readLine (). Ambil input dari konsol untuk nomor pertama lalu tekan enter. Setelah itu ambil input angka kedua seperti yang terlihat pada gambar di bawah ini:

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)

Keluaran

Shehzad Ali
sumber
2

Banyak jawaban usang untuk pertanyaan ini. Mulai Swift 2+, Perpustakaan Standar Swift berisi fungsi readline () . Ini akan mengembalikan Opsional tetapi hanya akan menjadi nihil jika EOF telah tercapai, yang tidak akan terjadi saat mendapatkan input dari keyboard sehingga dapat dibuka secara paksa dengan paksa dalam skenario tersebut. Jika pengguna tidak memasukkan apa pun, nilainya (tidak terbungkus) akan menjadi string kosong. Berikut adalah fungsi utilitas kecil yang menggunakan rekursi untuk meminta pengguna hingga setidaknya satu karakter telah dimasukkan:

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

Perhatikan bahwa menggunakan penjilidan opsional (jika let input = readLine ()) untuk memeriksa apakah ada sesuatu yang dimasukkan seperti yang diusulkan dalam jawaban lain tidak akan memiliki efek yang diinginkan, karena tidak akan pernah nol dan setidaknya "" saat menerima input keyboard.

Ini tidak akan berfungsi di Playground atau lingkungan lain di mana Anda tidak memiliki akses ke prompt perintah. Tampaknya ada masalah pada baris perintah REPL juga.

Andreas Bergström
sumber
1

Aku bersumpah demi Tuhan .. solusi untuk masalah yang benar-benar mendasar ini membuatku kabur selama bertahun-tahun. Sangat sederhana .. tetapi ada begitu banyak informasi yang tidak jelas / buruk di luar sana; semoga saya dapat menyelamatkan seseorang dari beberapa lubang kelinci tak berdasar yang akhirnya saya masuki ...

Jadi, mari kita dapatkan "string" dari "pengguna" melalui "konsol", melalui stdin, oke ?

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

jika Anda menginginkannya TANPA trailing newline, tambahkan saja ...

[ ... stringByTrimmingCharactersInSet:
                       NSCharacterSet.newlineCharacterSet];

Ta Da! ♥ ⱥ ᏪℯⅩ

Alex Gray
sumber
4
Swift, OP mengatakan Swift.
HenryRootTwo
1
Dia mengatakan osx. Itu semua dikompilasi ke hal yang sama! Rangkullah ObjC batin Anda!
Alex Grey
2
Ada orang yang menulis di Swift dan tidak akan pernah belajar Objective C. Ini bukan tentang apa yang dikumpulkannya.
HenryRootTwo
1

Swift 5: Jika Anda terus-menerus menginginkan input dari keyboard, tanpa mengakhiri program, seperti aliran input, Gunakan langkah-langkah di bawah ini:

  1. Buat proyek baru jenis alat baris comnnad Proyek baris perintah

    1. Tambahkan kode di bawah ini di file 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:")
      }   
      
    2. Jalankan Proyek dan klik yang dapat dieksekusi di bawah folder Produk di Xcode dan buka di finder
    3. Klik dua kali file yang dapat dieksekusi untuk membukanya.
    4. Sekarang masukkan Input Anda. Terminal akan terlihat seperti ini: masukkan deskripsi gambar di sini
Shikha Budhiraja
sumber
0

Karena tidak ada solusi yang bagus untuk masalah ini, saya membuat kelas kecil untuk membaca dan mengurai input standar di Swift. Anda bisa menemukannya di sini .

Contoh

Mengurai:

+42 st_ring!
-0.987654321 12345678900
.42

Anda melakukan:

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"
}
shoumikhin
sumber
Bagaimana cara mengimpor kelas StreamScanner?
Timothy Swan
@TimothySwan, seperti yang dijelaskan di bagian Instalasi Readme ( github.com/shoumikhin/StreamScanner#installation ). Jadi pada dasarnya Anda bisa menambahkan file StreamScanner.swift ke proyek Anda.
shoumikhin
0

Sebelum

masukkan deskripsi gambar di sini

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

Koreksi

masukkan deskripsi gambar di sini

Murphy
sumber
0

Ini berfungsi di xCode v6.2, saya pikir itu Swift v1.2

func input() -> String {
    var keyboard = NSFileHandle.fileHandleWithStandardInput()
    var inputData = keyboard.availableData
    return NSString(data: inputData, encoding:NSUTF8StringEncoding)! as String
}
Rusa Raksasa
sumber
0

Jika Anda ingin membaca string yang dipisahkan spasi, dan segera memisahkan string menjadi array, Anda dapat melakukan ini:

var arr = readLine()!.characters.split(" ").map(String.init)

misalnya.

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)")
Brian Ho
sumber
0

Saat fungsi readLine () dijalankan di Xcode, konsol debug menunggu masukan. Sisa kode akan dilanjutkan setelah input selesai.

    let inputStr = readLine()
    if let inputStr = inputStr {
        print(inputStr)
    }
Sourabh Shekhar
sumber
0

Jawaban peringkat teratas untuk pertanyaan ini menyarankan penggunaan metode readLine () untuk mengambil input pengguna dari baris perintah. Namun, saya ingin mencatat bahwa Anda perlu menggunakan! operator saat memanggil metode ini untuk mengembalikan string alih-alih opsional:

var response = readLine()!
topherPedersen
sumber
Why the force-unwrap, readLine()mengembalikan opsional karena suatu alasan, oleh karena itu tidak aman untuk membuka paksa dan tidak benar-benar menambahkan apa pun ke contoh.
Camsoft
0
var a;
scanf("%s\n", n);

Saya menguji ini di ObjC, dan mungkin ini akan berguna.


sumber
-1

Saya hanya ingin berkomentar (saya tidak memiliki cukup repetisi) tentang implementasi xenadu, karena CChardi OS X Int8, dan Swift sama sekali tidak suka ketika Anda menambahkan ke array ketika getchar()mengembalikan bagian UTF-8, atau apa pun di atas 7 bit.

Saya menggunakan array UInt8sebagai gantinya, dan itu berfungsi dengan baik dan String.fromCStringmengubahnya UInt8menjadi UTF-8 dengan baik.

Namun begitulah cara saya melakukannya

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)")
    }
}
aredigg
sumber
-1

Sekarang saya bisa mendapatkan input Keyboard di Swift dengan menggunakan berikut ini:

Dalam file main.swift saya, saya mendeklarasikan variabel i dan menugaskannya ke fungsi GetInt () yang saya definisikan di Objective C. Melalui apa yang disebut Bridging Header di mana saya mendeklarasikan prototipe fungsi untuk GetInt, saya bisa menautkan ke main.swift. Ini file-nya:

main.swift:

var i: CInt = GetInt()
println("Your input is \(i) ");

Bridging Header:

#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;
}

Dalam obj.m dimungkinkan untuk menyertakan keluaran dan masukan standar c, stdio.h, serta pustaka standar c stdlib.h yang memungkinkan Anda memprogram dalam C dalam Objective-C, yang berarti tidak perlu menyertakan file cepat yang nyata seperti user.c atau sesuatu seperti itu.

Semoga saya bisa membantu,

Sunting: Tidak mungkin mendapatkan input String melalui C karena di sini saya menggunakan CInt -> tipe integer C dan bukan Swift. Tidak ada tipe Swift yang setara untuk C char *. Oleh karena itu, String tidak dapat diubah menjadi string. Tetapi ada solusi yang cukup di sekitar sini untuk mendapatkan input String.

Raul

Raul Rao
sumber