テキストファイルから1行ずつ取得して処理したい場合、
bufio.Scanner を使いますね。
bufio.Scanner には、Splitというメソッドがあり、
行末の判断基準を変更することができるようです。
デフォルトでは、LF(\n)または、CRLF(\r\n)を見つけると行末(end-of-line)だと判断して、
1行分のデータを返してくれます。
(CRLFが除かれたデータを取得できます)
改行が CR(\r) だけの場合には、正しく動作してくれません。
ということで、Scannerがデフォルトで使用している ScanLines を元にして、
チョイ足しで、改行が CR(\r)だけの場合に対応してみました。
まずは、type SplitFunc を実装する必要があります。
bufio の ScanLines を基にして、
3ステップ追加しただけですが、、、
func CustomScan(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
var i int
if i = bytes.IndexByte(data, '\n'); i >= 0 {
// We have a full newline-terminated line.
return i + 1, dropCR(data[0:i]), nil
}
if i = bytes.IndexByte(data, '\r'); i >= 0 {
// ここを追加した。(CR があったら、そこまでのデータを返そう)
return i + 1, data[0:i], nil
}
// If we're at EOF, we have a final, non-terminated line. Return it.
if atEOF {
return len(data), dropCR(data), nil
}
// Request more data.
return 0, nil, nil
}
// dropCR drops a terminal \r from the data.
func dropCR(data []byte) []byte {
if len(data) > 0 && data[len(data)-1] == '\r' {
return data[0 : len(data)-1]
}
return data
}
このようなコードを自分のプログラムに追加して、
Splitメソッドに渡します。
func main() {
var fp *os.File
fp, _ = os.Open("./test.tsv")
defer fp.Close()
scanner := bufio.NewScanner(fp)
scanner.Split(CustomScan)
for scanner.Scan() {
// 1行ずつ処理する
....
}
}
それがどうした?って感じですが、
Atomエディタを使って、テキストファイルを作成したときに
改行が CR(\r) になってしまう現象に悩まされています。
Excel上のデータをコピーして、Atomにペースト(タブ区切り(TSV)の状態)すると発生します。
(解決策をご存知の方、教えてください。。。)
Atomエディタ側での解決策が見つからなかったので、bufioで何とかならんかとやってみた次第です。
もしかしたら、ReadString('\r') で対応してしまえばいいのかもしれませんが、
やっぱりCR,CRLFにも対応しておきたいし。
たいしたことはしていないですが、うまく動いたので良しです。