62939


[Bilingual Emacspeak
Project](http://www.argv.org/bep/)で英単語とその読みのカタカナの5万組ほどのペアのデータがGPLで公開されていたので  
これを使って英単語←→カタカナの変換を行うCUIのバイナリをGoで作ろうとしたのですが、一般的にこのような時にデータをどう保存しておくのかわからず躓いてしまいました。

思いついたのはデータの追加・削除は行わないのでmap形式でソースに直書きしてしまう方法とCSVなど扱いやすいデータをバイナリに同封する方法なのですが基礎的な知識が足りず方向性があってるのかさえわかりません。

上記のような条件ではGo言語でどのようにデータを取り扱うのが一般的なのでしょうか？


CC BY-SA 4.0
2020-02-10T10:59:31.180
62931
2020-02-10T23:05:52.387
3271
question
go
5万行程度のキーバリュー形式のデータをGo言語でバイナリで埋め込む時の方法について


標準パッケージの [gob](https://golang.org/pkg/encoding/gob/) を利用する方法を挙げます。

英単語を key, その読みのカタカナ表記を value とした map object を作成します。ここでは「読み」が複数ある英単語があるので
`map[string][]string` としています。次に map object を Deflate で圧縮、gob でエンコードして、`[]byte`
型変数(`BepDicByteArray`)の宣言文を作成します。

**generate.go**

[code]

    package main
    
    import (
      "bytes"
      "compress/flate"
      "encoding/csv"
      "encoding/gob"
      "fmt"
      "os"
    )
    
    func main() {
      tbl := make(map[string][]string)
      reader := csv.NewReader(os.Stdin)
      reader.Comma = ' '
      reader.FieldsPerRecord = -1
      for r, err := reader.Read(); err == nil; r, err = reader.Read() {
        tbl[r[0]] = append(tbl[r[0]], r[1])
      }
    
      buf := new(bytes.Buffer)
      out, _ := flate.NewWriter(buf, flate.DefaultCompression)
      if err := gob.NewEncoder(out).Encode(tbl); err != nil {
        panic(err)
      }
      out.Close()
    
      fmt.Printf("package main\n\nvar BepDicByteArray []byte = []byte{\n\t")
      for i, v := range buf.Bytes() {
        fmt.Printf("%#02x, ", v)
        if (i+1)%10 == 0 {
          fmt.Printf("\n\t")
        }
      }
      fmt.Printf("\n}")
    }
    
[/code]

**Generate bep_dic.go**

`generate.go` の出力をファイル(`bep_dic.go`)に保存します。

[code]

    $ tail -n +2 bep-eng.dic | nkf -w | go run generate.go > bep_dic.go
    
    $ head bep_dic.go
    package main
    
    var BepDicByteArray []byte = []byte{
        0x84, 0xfd, 0xfd, 0x6e, 0x1c, 0x47, 0x96, 0x36, 0x88, 0xb7, 
        0x46, 0xac, 0x4f, 0xd2, 0x56, 0xff, 0xfc, 0x42, 0x80, 0x00, 
                                  :
    
    $ ls -1sh bep-eng.dic bep_dic.go
    916K bep-eng.dic
    3.5M bep_dic.go
    
[/code]

**Example**

引数に英単語を取って、その「読み」(カタカナ表記)を表示します。対応する「読み」がない場合は "Not found." と表示します。

**main.go**

`[]byte` 型変数 BepDicByteArray に格納されている map object を復元します。

[code]

    package main
    
    import (
      "bytes"
      "compress/flate"
      "encoding/gob"
      "fmt"
      "os"
      "strings"
    )
    
    // Restore map object    
    func SetupDic() map[string][]string {
      buf := bytes.NewBuffer(BepDicByteArray)
      in := flate.NewReader(buf)
      dic := make(map[string][]string)
      if err := gob.NewDecoder(in).Decode(&dic); err != nil {
        panic(err)
      }
      in.Close()
    
      return dic
    }
    
    func main() {
      dic := SetupDic()
      if len(os.Args) > 1 {
        if r, ok := dic[strings.ToUpper(os.Args[1])]; ok {
          fmt.Println(r)
        } else {
          fmt.Println("Not found.")
        }
      }
    }
    
[/code]

**Build**

[code]

    $ go build -o bepdic main.go bep_dic.go
    
[/code]

**実行**

[code]

    $ ./bepdic accessories
    [アクセサリイズ アクセサリーズ]
    
    $ ./bepdic emacs
    [イマックス]
    
    $ ./bepdic vim
    [ヴィム]
    
    $ ./bepdic vi
    Not found.
    
[/code]


CC BY-SA 4.0
2020-02-10T19:01:10.377
62939
2020-02-10T23:05:52.387
2020-02-10T23:05:52.387
62931
answer


Goでもなんでも、５万件のデータをソースコードに書くということは普通しないと思います。

  * ５万行のソースコードをテストするのが面倒 
  * もはや保守不能

データが正しいかどうかとプログラムが正しいかどうかを分離して管理するほうが合理的なので。。

jsonで書き出しておいて、取り込むほうが楽なのでは？

<https://www.pospome.work/entry/20160828/1472385535>

同様にCSVでもできますね。この場合もファイルを読み込んで自分で解析するよりも  
すでにあるライブラリを利用するほうが合理的です。車輪の再発明はたのしいですけど、  
結局、品質おちるので

<http://nakawatch.hatenablog.com/entry/2018/05/29/184737>


CC BY-SA 4.0
2020-02-10T22:36:53.447
62941
2020-02-10T22:36:53.447
10174
62931
answer