コマンドラインアプリケーションでのキーボードからの入力


91

新しいAppleプログラミング言語Swiftのコマンドラインアプリのキーボード入力を取得しようとしています。

ドキュメントをスキャンして無駄にしました。

import Foundation

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

何か案は?

回答:


135

これを行う正しい方法はreadLine、Swift標準ライブラリのを使用することです。

例:

let response = readLine()

入力したテキストを含むオプションの値を提供します。


2
ありがとう。パスワードのような入力を取得する方法はありますか?
Abhijit Gaikwad 2016

私にとっては、response = nilでこの行を抜けます。問題は何ですか?
Peter Webb

4
@PeterWebb-xcodeターミナルで正常に動作し、遊び場でフォールスルーします:)
aprofromindia

2
readLineはほとんどの元の回答の後に追加されたので、態度は少し不当
ですIMHO

2
Swift 3、SlimJim
Ezekiel Elinの

62

私はなんとか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
}

5
:あなたが唯一のプログラムで一度入力を受け入れるために必要がある場合のように、関数を定義しない場合、私はこのように、また、それは、1行に圧縮することができますvar input = NSString(data: NSFileHandle.fileHandleWithStandardInput().availableData, encoding:NSUTF8StringEncoding)
jcmiller11

3
Playgroundでこれを使用してユーザー入力を即座に受け入れる方法はありますか?
ロブキャメロン

5
遊び場では使用できません。そこで変数を使用する必要があります。
チョーカー、2014年

8
これで文字列に改行が入ることに注意してください。それらstring.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet())
pk-nb

3
また、ユーザーが文字を削除したり、矢印キーを使用したりすると、奇妙な文字が表示されます。AAAGGGGGHHHHWHY、Swift、なぜですか
ybakos

13

実際にはそれほど簡単ではありません。CAPIを操作する必要があります。に代わるものはありませんscanf。私は小さな例を作成しました:

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

おやおや-これ以上に些細なことがあったらいいのに!これを文字列に適合させるのは難しいと思います。
チョーカー、2014年

1
関数定義を格納する「UserInput.h」を作成し、このファイルを「cliinput-Bridging-Header.h」にインクルードすることをお勧めします。
Alan Zhiliang Feng 2016

7

編集 Swift 2.2以降、標準ライブラリに含まれていreadLineます。Swiftがマークダウンドキュメントコメントに切り替わったことにも注目します。私の元の答えは歴史的な文脈に残しておきます。

完全を期すために、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) }
}

私はswiftdocコメントと「パブリック」アクセス修飾子が好きです。以前はSwiftでそのようなことを見たことがありませんでしたが、CCharとC-StringはCと8ビットの文字セットとSwiftへの逆戻りのようですすべてがUnicodeテキストに関するものなのか...またはコマンドラインツールはすべてASCIIなのか?
Kaydell 2014

2
getchar()はASCIIを返すと思います。Unicode端末は、私が知りたくなかったすべてのものです:)
russbishop

5

別の方法は、適切な行編集(矢印キーなど)とオプションの履歴サポートのためにlibeditをリンクすることです。私が始めているプロジェクトのためにこれが欲しかったし、それを設定する方法の基本的な例をまとめました

迅速からの利用

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

5

一般に、コンソールからの入力をスキャンするためにreadLine()関数が使用されます。ただし、「コマンドラインツール」を追加するまで、または追加しない限り、通常のiOSプロジェクトでは機能しません。

テストの最良の方法は、次のとおりです。

1. macOSファイルを作成する

ここに画像の説明を入力してください

2. readLine()funcを使用して、コンソールからオプションの文字列をスキャンします

 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

ここに画像の説明を入力してください


3

コンソールベースのアプリケーションでユーザーから入力を取得する簡単な例を次に示します。readLine()を使用できます。最初の番号をコンソールから入力して、Enterキーを押します。その後、下の画像に示すように、2番目の数値を入力します。

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)

出力


1

私はこれを解決..神に誓って全く基本的な問題は何年も前に私の目を逃れて。それはだSOシンプル ..しかし、そこにそんなに曖昧/悪い情報があります。うまくいけば、私は保存することができ、誰かからいくつかの底なしのウサギの穴私が終わったことを...

それでは、のは経由して、「コンソール」を介して「ユーザー」から「文字列」を取得することができますstdin我々はなりませんか

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

あなたがそれをしたい場合はなし改行、ちょうど追加...

[ ... stringByTrimmingCharactersInSet:
                       NSCharacterSet.newlineCharacterSet];

Ta Da! ♥ⱥᏪℯⅩ


4
スウィフト、OPはスウィフトを言います。
HenryRootTwo

1
彼はosxと言いました。それはすべて同じものにコンパイルされます!あなたの内側のObjCを受け入れてください!
Alex Grey

2
Swiftで記述し、Objective Cを決して学習しない人々がいます。これは、Swiftが何にコンパイルされるかということではありません。
HenryRootTwo 2016

1

この質問に対する多くの古い回答。Swift 2+以降、Swift標準ライブラリにはreadline()関数が含まれています。これはOptionalを返しますが、EOFに達した場合にのみnilになります。これはキーボードから入力を取得するときに発生しないため、これらのシナリオでは無理に強制的にラップを解除できます。ユーザーが何も入力しない場合、その(ラップされていない)値は空の文字列になります。再帰を使用して、少なくとも1つの文字が入力されるまでユーザーにプロンプ​​トを表示する小さなユーティリティ関数を次に示します。

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 let = readLine()の場合)を使用して、他の回答で提案されたとおりに何かが入力されたかどうかを確認することは、キーボード入力を受け入れるときにnilになることはなく、少なくとも ""になるため、望ましい効果はありません。

これは、コマンドプロンプトにアクセスできないPlaygroundやその他の環境では機能しません。コマンドラインREPLにも問題があるようです。


0

この問題に対する特別な解決策はなかったので、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"
}

StreamScannerクラスをインポートする方法は?
ティモシースワン

Readmeのインストールセクション(github.com/shoumikhin/StreamScanner#installation)で説明したように、@ TimothySwan。したがって、基本的には、StreamScanner.swiftファイルをプロジェクトに追加するだけです。
shoumikhin 2015


0

これは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
}

0

スペースで区切られた文字列を読み取り、すぐに文字列を配列に分割する場合は、次のようにします。

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

0

XcodeでreadLine()関数を実行すると、デバッグコンソールは入力を待ちます。入力が完了すると、残りのコードが再開されます。

    let inputStr = readLine()
    if let inputStr = inputStr {
        print(inputStr)
    }

0

この質問に対する上位の回答は、readLine()メソッドを使用してコマンドラインからユーザー入力を取り込むことを示唆しています。ただし、!を使用する必要があることに注意してください。オプションの代わりに文字列を返すためにこのメソッドを呼び出すときの演算子:

var response = readLine()!

なぜforce-unwrap readLine()が理由でオプションを返すのか、それゆえforce-unwrapは安全ではなく、実際には例に何も追加しません。
Camsoft

0

Swift 5:入力のストリームのように、プログラムを終了せずにキーボードからの入力を継続的に必要とする場合は、以下の手順を使用します。

  1. タイプcomnnadラインツールの新しいプロジェクトを作成する コマンドラインプロジェクト

    1. 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. プロジェクトを実行し、XcodeのProductsフォルダーの下の実行可能ファイルをクリックして、ファインダーで開きます
    3. 実行可能ファイルをダブルクリックして開きます。
    4. 次に、入力を入力します。ターミナルは次のようになります。 ここに画像の説明を入力してください


-1

xenaduの実装についてコメントしたい(十分な担当者がいない)のCCharInt8、OS X ではでありgetchar()、UTF-8の一部を返すときに配列に追加したり、7ビットを超えるものをSwiftがまったく好まなかったりするためです。

私はUInt8代わりにの配列を使用していますが、それはうまく機能し、UTF-8にうまくString.fromCString変換しUInt8ます。

しかし、これは私がそれをやった方法です

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

-1

以下を使用して、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();

obj.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と、Objective-CのCでプログラミングできるようにするc標準ライブラリstdlib.hを含めることができます。つまり、含める必要はありません。 user.cのような実際の迅速なファイルまたはそのようなもの。

お役に立てれば幸いです。

編集:ここではCInt-> Cの整数型を使用しており、Swiftの整数型を使用していないため、Cを介して文字列入力を取得することはできません。C char *に相当するSwiftタイプはありません。したがって、文字列は文字列に変換できません。しかし、文字列入力を取得するために、この辺りにはかなり十分な解決策があります。

ラウル

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.