2

私はGoを学び始めたばかりで、いくつかのメタデータを含むヘッダー付きのマークダウンファイルを解析する関数を作成しました(ファイルはブログ投稿です)。

ここに例があります:

---
Some title goes here
19 September 2012
---
This is some content, read it.

私はこの関数を作成しましたが、これは機能しますが、非常に冗長で厄介だと感じています。さまざまな文字列パッケージを確認しましたが、Goについて十分に理解しておらず、自分がどうあるべきかを知るためのベストプラクティスです。別の方法で、これをクリーンアップするためのヒントを得ることができれば、それをいただければ幸いです。(また、私はそのエラーを無視するべきではないことを知っています)。

type Post struct {
    Title string
    Date string
    Body string
}
func loadPost(title string) *Post {
    filename := title + ".md"
    file, _ := ioutil.ReadFile("posts/" + filename)
    fileString := string(file)
    str := strings.Split(fileString, "---")
    meta := strings.Split(str[1], "\n")
    title = meta[1]
    date := meta[2]
    body := str[2]
    return &Post{Title: title, Date: date, Body: body}
}
4

3 に答える 3

4

悪くないと思います。いくつかの提案:

  • 「posts/」のハードコーディングされたスラッシュは、プラットフォームに依存します。これを回避するには、path/filepath.Join を使用できます。
  • bytes.Split があるので、文字列(ファイル)は必要ありません。
  • フィールドを繰り返さずに投稿を作成できます。&Post{title, date, body}

または、本文がどこから始まるかを調べ、LastIndex(s, "--")それを使用してファイルの内容をそれに応じてインデックス付けすることもできます。これにより、Split を使用した割り当てが回避されます。

const sep = "--"

func loadPost(content string) *Post {
    sepLength := len(sep)

    i := strings.LastIndex(content, sep)
    headers := content[sepLength:i]
    body := content[i+sepLength+1:]

    meta := strings.Split(headers, "\n")

    return &Post{meta[1], meta[2], body}
}
于 2012-09-19T07:58:37.110 に答える
2

私はそれが悪くないことに同意します。他にもいくつかアイデアを追加します。

  • Thomasが示したように、中間変数titledateとbodyは必要ありません。でも試してみてください

    return &Post{
        Title: meta[1],
        Date: meta[2],
        Body: body,
    }
    

    フィールド名を省略できるのは事実ですが、コードを自己文書化しておくのが好きな場合もあります。(獣医も彼らが好きだと思います。)

  • 私は文字列とバイトスライスをめちゃくちゃにしていますが、おそらく私がすべき以上のものです。ファイルを一気に読んでいるので、おそらくこれについて心配する必要はありません。すべてを1つの大きな文字列に変換してから、文字列をスライスするのは便利な方法です。文字列の一部を保持している場合は、文字列全体をメモリに固定していることを忘れないでください。ファイルが大きい場合やファイルがたくさんあり、たとえばほとんどのファイルのメタを保持するだけの場合は、これが適切な方法ではない可能性があります。

  • ファイルごとにブログエントリは1つだけですか?もしそうなら、私はトーマスの提案の変形を提案すると思います。最初のバイトが---(またはファイルが破損している)であることを確認してから、strings.Index(fileString [3:]、 "---")を使用します。セグメントの数が不明な場合は、分割がより適切です。あなたの場合、あなたはメタの後にその単一のセパレーターを探しているだけです。インデックスは、メタを検索した後にそれを見つけて、全身を検索せずに実行されます。(とにかく、本文に文字列「---」が含まれている場合はどうなりますか?)

  • 最後に、これに正規表現を使用する人もいます。私はまだ正規表現にウォームアップしていませんが、とにかく、それは別のアプローチです。

于 2012-09-19T23:36:42.767 に答える
1

ソニアはいくつかの素晴らしい提案をしています。以下は、ヘッダーを解析するときに発生する可能性のある問題を説明する私の見解です。

http://play.golang.org/p/w-XYyhPj9n

package main

import (
    "fmt"
    "strings"
)

const sep = "---"

type parseError struct {
    msg string
}

func (e *parseError) Error() string {
    return e.msg
}

func parse(s string) (header []string, content string, err error) {
    if !strings.HasPrefix(s, sep) {
        return header, content, &parseError{"content does not start with `---`!"}
    }
    arr := strings.SplitN(s, sep, 3)
    if len(arr) < 3 {
        return header, content, &parseError{"header was not terminated with `---`!"}
    }
    header = strings.Split(strings.TrimSpace(arr[1]), "\n")
    content = strings.TrimSpace(arr[2])
    return header, content, nil
}

func main() {

    //
    f := `---
Some title goes here
19 September 2012
---
This is some content, read it. --Anonymous`

    header, content, err := parse(f)
    if err != nil {
        panic(err)
    }

    for i, val := range header {
        fmt.Println(i, val)
    }
    fmt.Println("---")
    fmt.Println(content)

    //
    f = `---
Some title goes here
19 September 2012
This is some content, read it.`

    _, _, err = parse(f)
    fmt.Println("Error:", err)

    //
    f = `
Some title goes here
19 September 2012
---
This is some content, read it.`

    _, _, err = parse(f)
    fmt.Println("Error:", err)
}
于 2012-09-19T23:53:45.877 に答える