2016-10-04 8 views
2

私は書いていますが、環境変数を含むファイル、つまりAPI_KEY=XYZを読む予定です。私はそれらをバージョン管理から守ることができます。以下の解決策は「うまくいく」が、おそらくもっと良い方法があるように感じる。このマップを解析する良い方法はありますか?

最後の目標は、 m["API_KEY"]のようにファイルから要素にアクセスできるようにすることで、XYZと表示されます。これはすでに存在していて、私はホイールを再発明しています.Goは環境変数を持っているのを見ましたが、それは私が具体的に行ったことではないようです。

どのような助けもありがとうございます。

Playground

コード:

package main 

import (
    "fmt" 
    "strings" 
) 

var m = make(map[string]string) 

func main() { 

    text := `Var1=Value1 
    Var2=Value2 
    Var3=Value3` 

    arr := strings.Split(text, "\n") 

    for _, value := range arr { 
     tmp := strings.Split(value, "=") 
     m[strings.TrimSpace(tmp[0])] = strings.TrimSpace(tmp[1]) 
    } 

    fmt.Println(m) 

} 
+0

もし仕事をしても、私はそれについて心配しません。 Goは洗練されたコードについてではなく、作業コードについてです... – RickyA

+1

それは失敗する可能性があるので、それにアクセスする前に '' len(tmp)> = 2''にテストを入れます( 'tmp [0]')。 – RickyA

+0

@RickyA非常に良い点は、実際にはエラーをチェックしていません。私が取り組んでいるものにそれを加えるでしょう、ありがとう。 – Mikey

答えて

4

まず、私はこの関連の質問を読むことをお勧めします:How to handle configuration in Go

次に、私は本当に別の形式で設定を保存検討します。あなたが提案するものは標準ではないからです。それはJava's property file format (.properties)に近いですが、プロパティファイルでさえUnicodeシーケンスを含んでいる可能性があります。したがって、コードはUnicodeシーケンスをまったく処理しないため、有効な.propertiesフォーマットパーサーではありません。

代わりにJSONを使用することをお勧めします.Goやその他の言語で簡単に解析でき、JSONテキストを編集するツールがたくさんありますが、それでも人にやさしいツールです。

JSON形式の場合、mapにデコードするのは、ただ1つの関数呼び出しです:json.Unmarshal()です。jsonパッケージには、書式設定し、あなたのためにエスケープ処理しますので、あなたは、任意の心配する必要はありません

map[Var1:Value1 Var2:Value2 Var3:Value3] 

text := `{"Var1":"Value1", "Var2":"Value2", "Var3":"Value3"}` 

var m map[string]string 
if err := json.Unmarshal([]byte(text), &m); err != nil { 
    fmt.Println("Invalid config file:", err) 
    return 
} 

fmt.Println(m) 

が出力(Go Playground上でそれを試してみてください):それはこのようになります。それらのまた、エラーを検出して報告します。また、JSONの方が柔軟性があり、設定に数値、テキスト、配列などが含まれている可能性があります。JSON形式を選択しただけで、すべて「無料」になります。

構成のもう1つの一般的な形式はYAMLですが、Go標準ライブラリにはYAMLパーサーが含まれていません。 Goの実装github.com/go-yaml/yamlを参照してください。

フォーマットを変更したくない場合は、投稿したコードを使用します。これは、入力行を1行ずつ処理し、name = valueからの対を解析します各行。 そしてそれは明確かつ明白な方法でそれを行います。この目的のためにCSVやその他のリーダーを使用するのは悪いです(彼らは意図的に正当な形式の詳細や変換を隠すため)。 CSVリーダは、 CSVリーダ最初にです。 tabulator/comma symbolを変更したとしても、は特定のエスケープシーケンスを解釈し、プレーンテキストエディタに表示されるものとは異なるデータを与えることがあります。これは意図していない動作ですが、あなたの入力はではなく、CSV形式のではなく、として CSVと解釈するよう読者に依頼しました。

あなたのソリューションに追加する改善点は、bufio.Scannerの使用です。これは、行単位で入力を読み込むために使用することができ、異なるスタイルの改行シーケンスを処理します。

text := `Var1=Value1 
Var2=Value2 
Var3=Value3` 

scanner := bufio.NewScanner(strings.NewReader(text)) 

m := map[string]string{} 
for scanner.Scan() { 
    parts := strings.Split(scanner.Text(), "=") 
    if len(parts) == 2 { 
     m[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) 
    } 
} 
if err := scanner.Err(); err != nil { 
    fmt.Println("Error encountered:", err) 
} 

fmt.Println(m) 

出力は同じです。 Go Playgroundで試してみてください。 bufio.Scannerを使用して

は別の利点があります:bufio.NewScanner()は、「すべてのものは、バイトの源である」のための一般的なインターフェース、io.Readerを受け入れます。これは、設定がファイルに保存されていて、すべての設定をメモリに読み込む必要がなくても、そのファイルを開くことができます。 os.Open()*os.Fileの値を返します。*os.Fileの値をbufio.NewScanner()に直接渡すことができます(したがって、bufio.Scannerは上記の例のようなメモリ内のバッファからではなくファイルから読み込みます)。

+1

本当にそれを賛美することはできません。華麗な答えです。主に私が平文形式を選んだ唯一の理由は、それが他の言語で扱われたのを見ているからです。私はあなたの答えを完全に消化した後にあなたが読んだことを言いました。おかげで:D – Mikey

+0

@ピジョンそれをさらに有益/有益にするためにいくつかの編集を加えました。 – icza

3

1 - あなたはとencoding/csvからcsv.NewReaderを使用してちょうど1の関数呼び出しr.ReadAll()ですべてを読むことがあります。

r.Comma = '=' 
r.TrimLeadingSpace = true 

、結果が[][]string、およびです入力順が保存されます、試してみてくださいThe Go Playground

package main 

import (
    "encoding/csv" 
    "fmt" 
    "strings" 
) 

func main() { 
    text := `Var1=Value1 
    Var2=Value2 
    Var3=Value3` 

    r := csv.NewReader(strings.NewReader(text)) 
    r.Comma = '=' 
    r.TrimLeadingSpace = true 

    all, err := r.ReadAll() 
    if err != nil { 
     panic(err) 
    } 
    fmt.Println(all) 
} 

出力:

[[Var1 Value1] [Var2 Value2] [Var3 Value3]] 

2 - あなたはThe Go Playground上でそれを試して、順序がに保存されていないマップへの出力を変換するためにcsv.ReadAll()を微調整するかもしれないが、 :

package main 

import (
    "encoding/csv" 
    "fmt" 
    "io" 
    "strings" 
) 

func main() { 
    text := `Var1=Value1 
    Var2=Value2 
    Var3=Value3` 
    r := csv.NewReader(strings.NewReader(text)) 
    r.Comma = '=' 
    r.TrimLeadingSpace = true 
    all, err := ReadAll(r) 
    if err != nil { 
     panic(err) 
    } 
    fmt.Println(all) 
} 

func ReadAll(r *csv.Reader) (map[string]string, error) { 
    m := make(map[string]string) 
    for { 
     tmp, err := r.Read() 
     if err == io.EOF { 
      return m, nil 
     } 
     if err != nil { 
      return nil, err 
     } 
     m[tmp[0]] = tmp[1] 
    } 
} 

ou TPUT:

map[Var2:Value2 Var3:Value3 Var1:Value1] 
+0

これは興味深いことですが、 'strings.TrimSpace()'で空白を整えたい場合は、要素をループして更新するか、csvに適用する方法がありますリーダー?ちょうど私は '[Var2 Value2]'を避けることができます – Mikey

+0

興味深い見て、他の誰かが何か提案がある場合に表示されます。そうでない場合、私はこの回答を後で受け入れます。 – Mikey

関連する問題