Go言語におけるio/ioutilとbufioで標準入力を行う方法

Go

はじめに

AtCoderの競技プログラミングや最近ではプログラマなどのIT関連の転職などでもプログラミングテストがありますが、そこでよく見られるのが標準入力を元に問題を解くようなものです。
しかし、普段プログラマをしている人にはあまり標準入力に馴染みのないエンジニアも多くいるのではないでしょうか?
そこで今回はgo言語で利用できる標準入力の方法を紹介します

流行りに乗ってGo言語を使ってみた(インストールからHelloWorld表示まで)
Go言語とは 2009年、GoogleでRobert Griesemer、ロブ・パイク、ケン・トンプソンによって設計された。Goは、静的型付け、C言語の伝統に則ったコンパイル言語、メモリ安全性、ガベージコレクション、構造的型付け(英語版)、...

流行りに乗ってGo言語を使ってみた(インストールからHelloWorld表示まで)

io/ioutilを使用した標準入力の読み込み

io/ioutilパッケージのReadAll関数を使用すると、標準入力を一度にすべて読み込むことができます。これは短いテキストを入力する際に便利ですが、大量のデータを扱う場合にはメモリの消費が懸念されます。

package main

import (
    "fmt"
    "io/ioutil"
    "os"
)

func main() {
    data, err := ioutil.ReadAll(os.Stdin)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(data))
}

上記のコードを実行して、テキストを入力するとそのまま出力されます。

複数行を扱う場合のサンプルコード

ioutilを使用して、複数行の標準入力を一度に読み取る方法もあります。以下はそれを示すサンプルコードです。

package main

import (
    "fmt"
    "io/ioutil"
    "os"
)

func main() {
    data, err := ioutil.ReadAll(os.Stdin)
    if err != nil {
        panic(err)
    }
    allText := strings.Split(string(data),"\n")
    fmt.Println(allText)
}

ioutil.ReadAllでは改行コードの含めたすべての文字列が取得できるため、複数行ありそれぞれの行を取得したい場合は改行コード(\n)で文字列を区切ることによって使用することができます。

bufioを使用した標準入力の読み込み

bufioパッケージは、バッファリングされたI/O操作を提供しています。これにより、行ごとやトークンごとにデータを読み込むことが可能となります。

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        panic(err)
    }
}

上記のコードは、入力された各行を読み取り、そのまま出力します。この方法は、大量のデータやストリームデータを効率的に処理する際に有効です。

複数行を扱う場合のサンプルコード

次に、bufioを使用して複数行の入力を一度に読み取り、それを一つの文字列として結合するサンプルコードを示します。

package main

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

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    var lines []string
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    if err := scanner.Err(); err != nil {
        panic(err)
    }
    allText := strings.Join(lines, "\n")
    fmt.Println(allText)
}

このコードでは、入力された各行をlinesに保存し、入力が終了したらstrings.Joinを使用してそれらの行を結合します。結果は一つの文字列として出力されます。scanner.Scan()を呼び出すことで1行を読み込むことができます

どちらを使うべきか

どちらの方法を選ぶかは、使用ケースに応じて異なります。短い入力データを一度に読み取る場合、io/ioutilReadAllが適しています。一方、大きなデータを効率的に扱いたい場合や、行ごとの処理が必要な場合はbufioを使用するのが良いでしょう。

参考リンク

まとめ

Go言語の標準ライブラリには、標準入力を扱うための多くの関数と方法が提供されています。io/ioutilbufioは、それぞれ異なる使用ケースに適した機能を持っています。適切な方法を選択することで、効率的なコードの実装が可能となります。