[英]Input from the keyboard in command line application
我正在嘗試為新的 Apple 編程語言 Swift 獲取命令行應用程序的鍵盤輸入。
我已經掃描了文檔無濟於事。
import Foundation
println("What is your name?")
???
有任何想法嗎?
我設法弄明白了,而沒有掉到 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
}
這實際上並不那么容易,您必須與 C API 進行交互。 scanf
沒有其他選擇。 我已經建立了一個小例子:
main.swift
import Foundation
var output: CInt = 0
getInput(&output)
println(output)
用戶輸入文件
#include <stdio.h>
void getInput(int *output) {
scanf("%i", output);
}
cliinput-Bridging-Header.h
void getInput(int *output);
通常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
編輯從 Swift 2.2 開始,標准庫包括readLine
。 我還會注意到 Swift 切換到了 Markdown 文檔注釋。 留下我對歷史背景的原始答案。
為了完整readln
,這里是我一直在使用的readln
的 Swift 實現。 它有一個可選參數來指示您要讀取的最大字節數(可能是也可能不是字符串的長度)。
這也演示了 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) }
}
另一種選擇是鏈接libedit以進行正確的行編輯(箭頭鍵等)和可選的歷史支持。 我想要這個用於我正在啟動的項目,並 為我如何設置它整理了一個 基本示例。
來自 swift 的用法
let prompt: Prompt = Prompt(argv0: C_ARGV[0])
while (true) {
if let line = prompt.gets() {
print("You typed \(line)")
}
}
用於公開 libedit 的 ObjC 包裝器
#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()函數。 它將返回一個 Optional 但只有在達到 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())檢查是否按照其他答案中的建議輸入了某些內容將不會產生預期的效果,因為在接受鍵盤輸入時它永遠不會為零並且至少為 ""。
這在 Playground 或您無權訪問命令提示符的任何其他環境中不起作用。 命令行 REPL 中似乎也有問題。
Swift 5 :如果您一直希望從鍵盤輸入,而不像輸入流那樣結束程序,請使用以下步驟:
我向上帝發誓......這個完全基本問題的解決方案讓我多年來一直沒有找到。 這太簡單了……但是那里有太多模糊/錯誤的信息; 希望我能挽救一些無底的人的兔子洞,我在結束了...
那么,讓我們開始從“用戶”通過“控制台”一“串”,通過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)")
當在 Xcode 上運行 readLine() 函數時,調試控制台等待輸入。 其余代碼將在輸入完成后恢復。
let inputStr = readLine()
if let inputStr = inputStr {
print(inputStr)
}
這個問題排名靠前的答案建議使用 readLine() 方法從命令行接收用戶輸入。 但是,我要注意的是,您需要使用 ! 調用此方法以返回字符串而不是可選值時的運算符:
var response = readLine()!
var a;
scanf("%s\n", n);
我在 ObjC 中對此進行了測試,也許這會很有用。
import Foundation
print("Enter a number")
let number : Int = Int(readLine(strippingNewline: true)!) ?? 0
if(number < 5)
{
print("Small")
}else{
print("Big")
}
for i in 0...number{
print(i)
}
我只是想評論(我沒有足夠的代表)在xenadu的實現,因為CChar
在OS X是Int8
,當你添加到陣列時,斯威夫特不喜歡在所有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 並將我在 Objective C 中定義的函數 GetInt() 分配給它。通過一個所謂的橋接頭,我在其中聲明了 GetInt 的函數原型,我可以鏈接到 main.swift。 以下是文件:
main.swift:
var i: CInt = GetInt()
println("Your input is \(i) ");
橋接標題:
#include "obj.m"
int GetInt();
對象.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,它使您能夠在 Objective-C 中使用 C 進行編程,這意味着不需要包括一個真正的 swift 文件,比如 user.c 或類似的東西。
希望我能幫上忙
編輯:不可能通過 C 獲得字符串輸入,因為在這里我使用的是 CInt -> C 的整數類型而不是 Swift。 C char* 沒有等效的 Swift 類型。 因此字符串不能轉換為字符串。 但是這里有足夠多的解決方案來獲取字符串輸入。
勞爾
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.