Go言語での標準入力処理 [paiza用]

# 追記

2017/02/04

- 入力行数無指定のデータ列に対応した関数を追加しました。
- コメントを少し追加しました。

# 概要

Go言語修行僧です。

paizaのサンプルコードにGoの標準入力ソース例がないってのは、どういうことですかね?
などと言ってみたりします。

以下の実装は、Go言語において、paizaからの標準入力を受け取ってデータ処理をするために特化した関数群です。packageにしてもpaizaだと単一ファイルでの実装になるので意味がないのでpackage化していません。

どちらかというと自分用メモですが、[この記事](http://qiita.com/zurazurataicho/items/e66645bac16d9a482369)([Goで標準入力から文字列や数値列を取得する](http://qiita.com/zurazurataicho/items/e66645bac16d9a482369))からの派生というか、この記事に書かれた方法だけでは対応できない設問の入力があったので(改行コードの問題?)、一括入力してスライスに詰め直すなどの処理をする関数を作成したものです。

paizaのスキルチェックで入力処理が自作できなくても、本質であるプロセスやアルゴリズムなどがしっかり実装できればスキルはあるだろうという認識ですので、このコードが他のpaiza利用者に使われても大きな問題はないだろうという認識のもと、ここにまとめておく次第です(基本、チートやコピペ職人似非エンジニアは嫌いなので)。

# ソースコード

こんな感じです。必要に応じて適当に調整してください(たぶんそういう場面がでてくるはず)。特に解説はしません。
とりあえず、このコード作るのにsliceの使い方がある程度理解できたのは大きな獲得でした(個人的なコトですが…)。

あ、paizaは入力固定だという認識なので、特段エラー処理はしていません。

バグがあったら適宜修正入れます。
もっとかしこい方法があったら教えてください m(_ _)m

```go:paiza専用標準入力
package main

import (
        "bufio"
        "fmt"
        "os"
        "strconv"
        "strings"
)

// 空白や空文字だけの値を除去したSplit()
func SplitWithoutEmpty(stringTargeted string, delim string) (stringReturned []string) {
        stringSplited := strings.Split(stringTargeted, delim)

        for _, str := range stringSplited {
                if str != "" {
                        stringReturned = append(stringReturned, str)
                }
        }

        return
}

// 空白や空文字だけの値を除去したSplitN()
func SplitWithoutEmptyN(stringTargeted string, delim string, n int) (stringReturned []string) {
        stringSplited := strings.SplitN(stringTargeted, delim, n)

        for _, str := range stringSplited {
                if str != "" {
                        stringReturned = append(stringReturned, str)
                }
        }

        return
}

// デリミタで分割して整数値スライスを取得
func SplitAndConvertToInt(stringTargeted, delim string) (intSlices []int, err error) {
        // 分割
        stringSplited := SplitWithoutEmpty(stringTargeted, delim)

        // 整数スライスに保存
        for i := range stringSplited {
                var iparam int
                iparam, err = strconv.Atoi(stringSplited[i])
                if err != nil {
                        return
                }
                intSlices = append(intSlices, iparam)
        }
        return
}

/**
 * paiza専用: 行指定なしデータ列読み込み
 *
 */
func PaizaSequenceGetsAsInt() (line [][]int) {
        scanner := bufio.NewScanner(os.Stdin)

        for scanner.Scan() {
                str := scanner.Text()
                data, err := SplitAndConvertToInt(str, " ")
                if err != nil || data == nil {
                        break
                }
                line = append(line, data)
        }

        return
}

/**
 * paiza専用: 行指定なし文字列読み込み
 *
 */
func PaizaSequenceGets() (lines [][]string) {
        scanner := bufio.NewScanner(os.Stdin)

        for scanner.Scan() {
                str := scanner.Text()
                data := SplitWithoutEmpty(str, " ")
                if data == nil {
                        break
                }
                lines = append(lines, data)
        }

        return
}

/**
 * paiza専用: 「文字 数値 数値 数値...」の取得
 *
 */
func PaizaStrFirstIntAfter(data string, delim string) (head string, body []int) {
        list := SplitWithoutEmptyN(data, delim, 2)
        head = list[0]
        body, _ = SplitAndConvertToInt(list[1], delim)
        return
}

/**
 * paiza専用: 文字列一括取得・最初X,Y、以下Y行文字列
 *
 */
func PaizaGetsXY() (x, y int, line []string) {
        scanner := bufio.NewScanner(os.Stdin)

        first := true
        for scanner.Scan() {
                str := scanner.Text()
                if first {
                        xy, _ := SplitAndConvertToInt(str, " ")
                        x = xy[0]
                        y = xy[1]
                        first = false
                } else {
                        line = append(line, strings.TrimSpace(str))
                }
        }

        return
}

/**
 * paiza専用: 文字列一括取得・最初行数、以下文字列
 *
 */
func PaizaGets() (count int, line []string) {
        scanner := bufio.NewScanner(os.Stdin)

        n := -1
        for scanner.Scan() {
                str := scanner.Text()
                if n == -1 {
                        count, _ = strconv.Atoi(strings.TrimSpace(str))
                } else {
                        line = append(line, strings.TrimSpace(str))
                }
                n += 1

                if n >= count {
                        break
                }
        }

        return
}

/**
 * paiza専用: 数字列1行取得・1整数以上対応
 *
 */
func PaizaGetNums() (intReturned []int) {
        scanner := bufio.NewScanner(os.Stdin)

        scanner.Scan()
        str := scanner.Text()
        intReturned, _ = SplitAndConvertToInt(str, " ")

        return
}

/**
 * paiza専用: 文字列取得・複数単語
 *
 */
func PaizaGetWordList() (stringReturned []string) {
        scanner := bufio.NewScanner(os.Stdin)

        scanner.Scan()
        str := scanner.Text()
        stringReturned = SplitWithoutEmpty(str, " ")

        return
}

/**
 * paiza専用: 文字列取得・1単語
 *
 */
func PaizaGetWord() (stringReturned string) {
        scanner := bufio.NewScanner(os.Stdin)

        scanner.Scan()
        stringReturned = scanner.Text()

        return
}

///////////////////////////////////
// 使い方サンプル
///////////////////////////////////

// 1行・文字・1単語
func TestPaizaGetWord() {
        line := PaizaGetWord()
        fmt.Println(line)
}

// 1行・文字・複数単語
func TestPaizaGetWordList() {
        list := PaizaGetWordList()
        for _, str := range list {
                fmt.Println(str)
        }
}

// 1行・数値・空白区切り対応
func TestPaizaGetNum() {
        nums := PaizaGetNums()
        fmt.Println(nums)
        // 数値であることを示すため
        if len(nums) >= 2 {
                fmt.Printf("%d+%d=%d\n", nums[0], nums[1], nums[0]+nums[1])
        } else {
                fmt.Printf("%d*2=%d\n", nums[0], nums[0]*2)
        }
}

// 1行目.......継続行数
// 2行目以降...文字列(空白区切り)
func TestPaizaGets() {
        count, line := PaizaGets()
        fmt.Printf("count=%d\n", count)
        for _, d := range line {
                strs := SplitWithoutEmpty(d, " ")
                fmt.Println(strs)
        }
}

// 1行目.......継続行数
// 2行目以降...文字、整数値列(空白区切り)
func TestPaizaStrFirstIntAfter() {
        count, line := PaizaGets()
        fmt.Printf("count=%d\n", count)
        for _, d := range line {
                head, body := PaizaStrFirstIntAfter(d, " ")
                fmt.Println(head)
                fmt.Println(body)
                fmt.Printf("%d+%d=%d\n", body[0], body[1], body[0]+body[1]) // 数値であることを示すため
        }
}

// 1行目.......2整数(x yなど)
// 2行目以降...文字列(空白区切り)
func TestPaizaGetsXY() {
        x, y, line := PaizaGetsXY()
        fmt.Printf("(x,y)=(%d,%d)\n", x, y)
        for _, d := range line {
                strs := SplitWithoutEmpty(d, " ")
                fmt.Println(strs)
        }
}

// 改行のみ続くまで数値列入力
func TestPaizaSequenceGetsAsInt() {
        line := PaizaSequenceGetsAsInt()
        for _, d := range line {
                fmt.Println(d)
                fmt.Printf("%d+%d+%d=%d\n", d[0], d[1], d[2], d[0]+d[1]+d[2])
        }
}

// 改行のみ続くまで文字列入力
func TestPaizaSequenceGets() {
        line := PaizaSequenceGets()
        for i, d := range line {
                fmt.Printf("-- %d --\n", i)
                for _, s := range d {
                        fmt.Printf("%s\n", s)
                }
        }
}

// main()
func main() {
        /**
         * 1行・数値・複数整数(空白区切りのない整数値も可)
         *
         * 入力例)
         * 12 34 56
         */
        TestPaizaGetNum()

        /**
         * 1行・文字・1単語
         *
         * 入力例)
         * foo
         */
        TestPaizaGetWord()

        /**
         * 1行・文字・複数単語
         *
         * 入力例)
         * foo bar baz
         */
        TestPaizaGetWordList()

        /**
         * 1行目.......継続行数
         * 2行目以降...文字列(空白区切り)
         *
         * 入力例)
         * 3
         * AA BB CC
         * DD EE FF
         * GG HH II
         */
        TestPaizaGets()

        /**
         * 1行目.......継続行数
         * 2行目以降...文字、整数値列(空白区切り)
         *
         * 入力例)
         * 3
         * A 10 20 30
         * B 11 22 33
         * C 99 88 77
         */
        TestPaizaStrFirstIntAfter()

        /**
         * 1行目.......2整数(x yなど)
         * 2行目以降...文字列(空白区切り)
         *
         * 入力例)
         * 2 3
         * AA BB CC
         * XX YY ZZ
         */
        TestPaizaGetsXY()

        /**
         * 改行のみ続くまで数値列入力
         *
         * 入力例)
         * 2 3 4
         * 11 12 34
         * 9 87 654
         *    :
         *    :
         * (空行)
         */
        TestPaizaSequenceGetsAsInt()

        /**
         * 改行のみ続くまで文字列入力
         *
         * 入力例)
         * foo bar baz
         * hoge fuga
         * piyo
         * AA BB
         *    :
         *    :
         * (空行)
         */
        TestPaizaSequenceGets()
}
```