Yeni Apple programlama dili Swift için bir komut satırı uygulaması için klavye girişi almaya çalışıyorum.
Belgeleri boşuna taradım.
import Foundation
println("What is your name?")
???
Herhangi bir fikir?
Yanıtlar:
Bunu yapmanın doğru yolu readLine
, Swift Standard Kitaplığından kullanmaktır.
Misal:
let response = readLine()
Girilen metni içeren bir İsteğe bağlı değer verecektir.
C'ye düşmeden çözmeyi başardım:
Benim çözümüm aşağıdaki gibidir:
func input() -> String {
var keyboard = NSFileHandle.fileHandleWithStandardInput()
var inputData = keyboard.availableData
return NSString(data: inputData, encoding:NSUTF8StringEncoding)!
}
Xcode'un daha yeni sürümleri, açık bir typecast'e ihtiyaç duyar (Xcode 6.4'te çalışır):
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())
Aslında o kadar kolay değil, C API ile etkileşime girmeniz gerekiyor. Bunun alternatifi yok scanf
. Küçük bir örnek oluşturdum:
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);
düzenleme Swift 2.2'den itibaren standart kitaplık içerir readLine
. Swift'in belge yorumlarını işaretlemek için değiştirildiğini de not edeceğim. Orijinal cevabımı tarihsel bağlam için bırakıyorum.
Tamlık adına, burada kullandığım bir Swift uygulaması var readln
. Okumak istediğiniz maksimum bayt sayısını (String'in uzunluğu olabilir veya olmayabilir) belirtmek için isteğe bağlı bir parametreye sahiptir.
Bu aynı zamanda swiftdoc yorumlarının doğru kullanımını gösterir - Swift bir <project> .swiftdoc dosyası oluşturur ve Xcode onu kullanır.
///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) }
}
Genel olarak readLine () işlevi konsoldan giriş taramak için kullanılır. Ancak, siz "komut satırı aracı" eklemediğiniz sürece normal iOS projesinde çalışmayacaktır .
Test etmenin en iyi yolu şunları yapabilirsiniz:
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
Diğer bir alternatif, düzgün satır düzenleme (ok tuşları, vb.) Ve isteğe bağlı geçmiş desteği için libedit'i bağlamaktır . Bunu, başladığım bir proje için istedim ve onu nasıl kurduğuma dair temel bir örnek oluşturdum .
Swift'den kullanım
let prompt: Prompt = Prompt(argv0: C_ARGV[0])
while (true) {
if let line = prompt.gets() {
print("You typed \(line)")
}
}
Libedit'i ortaya çıkarmak için ObjC sarıcı
#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
Konsol tabanlı uygulamada kullanıcıdan girdi almanın basit bir örneği: readLine () kullanabilirsiniz. İlk numara için konsoldan giriş alın ve ardından enter tuşuna basın. Bundan sonra, aşağıdaki resimde gösterildiği gibi ikinci numarayı girin:
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)
Bu soruya birçok modası geçmiş cevap. Swift 2+ itibariyle Swift Standart Kitaplığı, readline () işlevini içerir. Bir İsteğe Bağlı döndürür, ancak yalnızca EOF'ye ulaşıldığında sıfır olacaktır, bu, klavyeden girdi alınırken gerçekleşmez, böylece bu senaryolarda zorla açılabilir. Kullanıcı herhangi bir şey girmezse (sarılmamış) değeri boş bir dizge olacaktır. İşte, en az bir karakter girilene kadar kullanıcıyı uyarmak için özyinelemeyi kullanan küçük bir yardımcı program işlevi:
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)")
Bir şeyin diğer cevaplarda önerildiği gibi girilip girilmediğini kontrol etmek için isteğe bağlı bağlama (let input = readLine ()) kullanmanın istenen etkiyi yaratmayacağına dikkat edin, çünkü bu hiçbir zaman sıfır olmayacak ve en azından klavye girişi kabul edilirken "" olacaktır.
Bu, Oyun Alanında veya komut istemine erişiminizin olmadığı başka herhangi bir ortamda çalışmayacaktır. REPL komut satırında da sorunlar var gibi görünüyor.
Yemin ederim .. Bu son derece basit sorunun çözümü yıllarca benden kaçtı. Çok basit .. ama orada çok fazla belirsiz / kötü bilgi var; umarım ben kaydedebilirsiniz birisini gelen bazı dipsiz bir tavşan delikleri ben bitti o ...
Öyleyse, "konsol" aracılığıyla "kullanıcıdan" bir "dizgi" alalımstdin
, olur mu?
[NSString.alloc initWithData:
[NSFileHandle.fileHandleWithStandardInput availableData]
encoding:NSUTF8StringEncoding];
son satırda OLMADAN istiyorsanız , sadece ekleyin ...
[ ... stringByTrimmingCharactersInSet:
NSCharacterSet.newlineCharacterSet];
Ta Da!
♥ ⱥ ᏪℯⅩ
Swift 5: Programı sonlandırmadan, sürekli olarak klavyeden giriş yapmak istiyorsanız, bir giriş akışı gibi, aşağıdaki adımları kullanın:
Comnnad çizgi aracı türünde yeni proje oluştur
Main.swift dosyasına aşağıdaki kodu ekleyin:
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:")
}
Bu soruna süslü çözümler olmadığından, Swift'deki standart girişi okuyup ayrıştırmak için küçük bir sınıf yaptım. Burada bulabilirsiniz .
Misal
Ayrıştırmak için:
+42 st_ring!
-0.987654321 12345678900
.42
Yapmalısın:
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"
}
Boşlukla ayrılmış dizeyi okumak ve dizeyi hemen bir diziye bölmek istiyorsanız, bunu yapabilirsiniz:
var arr = readLine()!.characters.split(" ").map(String.init)
Örneğin.
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 () işlevi Xcode üzerinde çalıştırıldığında, hata ayıklama konsolu giriş için bekler. Kodun geri kalanı, giriş yapıldıktan sonra devam edecektir.
let inputStr = readLine()
if let inputStr = inputStr {
print(inputStr)
}
Bu sorunun en üst sıradaki yanıtı, komut satırından kullanıcı girişi almak için readLine () yönteminin kullanılmasını önerir. Ancak, kullanmanız gerektiğini belirtmek isterim! isteğe bağlı yerine bir dize döndürmek için bu yöntemi çağırırken operatör:
var response = readLine()!
readLine()
isteğe bağlı olarak dönüyor, bu nedenle zorla sarmayı açmak güvensizdir ve örneğe gerçekten hiçbir şey eklemez.
var a;
scanf("%s\n", n);
Bunu ObjC'de test ettim ve belki bu faydalı olabilir.
Sadece xenadu uygulaması hakkında yorum yapmak istedim (yeterli tekrarım yok), çünkü CChar
OS X'de Int8
ve Swift, getchar()
UTF-8'in parçalarını veya 7 bitin üzerindeki herhangi bir şeyi döndürdüğünde diziye eklediğinizde hiç hoşlanmıyor .
Bunun UInt8
yerine bir dizi kullanıyorum ve harika çalışıyor ve UTF-8'e String.fromCString
dönüştürüyor UInt8
.
Ancak ben böyle yaptım
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)")
}
}
Artık aşağıdakileri kullanarak Swift'de Klavye girişi yapabildim:
Main.swift dosyamda bir i değişkenini tanımladım ve ona Objective C'de tanımladığım GetInt () fonksiyonunu atadım. GetInt için fonksiyon prototipini ilan ettiğim sözde Bridging Header aracılığıyla main.swift'e bağlanabilirdim. İşte dosyalar:
main.swift:
var i: CInt = GetInt()
println("Your input is \(i) ");
Köprüleme Başlığı:
#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'de c standart çıktı ve girdisi stdio.h ile birlikte Objective-C'de C programlamanızı sağlayan stdlib.h c standart kitaplığını dahil etmek mümkündür, bu da dahil etmeye gerek olmadığı anlamına gelir user.c gibi gerçek bir hızlı dosya veya bunun gibi bir şey.
Umarım yardım edebilirim
Düzenleme: C aracılığıyla String girdisi almak mümkün değil çünkü burada Swift'in değil, CInt -> C'nin tamsayı türünü kullanıyorum. C karakter * için eşdeğer bir Swift türü yoktur. Bu nedenle String, dizeye dönüştürülemez. Ancak burada String girdisi almak için oldukça yeterli çözüm var.
Raul