[英]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.