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?
Jawaban:
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.
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
}
var input = NSString(data: NSFileHandle.fileHandleWithStandardInput().availableData, encoding:NSUTF8StringEncoding)
string.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet())
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);
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 readln
telah 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) }
}
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:
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
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
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)
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.
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!
♥ ⱥ ᏪℯⅩ
Swift 5: Jika Anda terus-menerus menginginkan input dari keyboard, tanpa mengakhiri program, seperti aliran input, Gunakan langkah-langkah di bawah ini:
Buat proyek baru jenis alat baris comnnad
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:")
}
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"
}
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
}
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)")
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)
}
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()!
readLine()
mengembalikan opsional karena suatu alasan, oleh karena itu tidak aman untuk membuka paksa dan tidak benar-benar menambahkan apa pun ke contoh.
var a;
scanf("%s\n", n);
Saya menguji ini di ObjC, dan mungkin ini akan berguna.
Saya hanya ingin berkomentar (saya tidak memiliki cukup repetisi) tentang implementasi xenadu, karena CChar
di 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 UInt8
sebagai gantinya, dan itu berfungsi dengan baik dan String.fromCString
mengubahnya UInt8
menjadi 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)")
}
}
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