2012-09-19 50 views
2

我剛剛開始學習Go,並且製作了一個函數,該函數使用包含一些元數據(文件是博客文章)的標題解析標記文件。有沒有辦法清理這個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} 
} 
+2

甲側面說明:[黑色星期五](https://github.com/russross/blackfriday)可以降價一個完整的,天然的圍棋解析器。 – jimt

+0

謝謝,我一直在使用不同的md解析器(https://github.com/hoisie/mustache),但blackfriday看起來更精美一些。 – Zen

+0

不要忽略'ioutil.ReadFile'的錯誤!將其返回,記錄或者恐慌 - 忽略它會在未來導致難以調試的問題。 –

回答

4

我認爲這不壞。幾點建議:

  • 「posts /」中的硬編碼斜槓是平臺相關的。你可以使用path/filepath.Join來避免這種情況。
  • 有bytes.Split,所以你不需要字符串(文件)。
  • 您可以在不重複的字段創建帖子:&Post{title, date, body}

或者,你可以找出身體與LastIndex(s, "--")開始,該文件的內容相應地使用該索引。這避免了使用分割的分配。

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} 
} 
+0

我不認爲'LastIndex'會在這裏使用,因爲它非常貪婪。文中可能會出現更多的「---」。但+1分裂從解析內容中讀取的文件。 – nemo

+0

感謝您的意見,夥計們。它看起來更好! – Zen

2

我同意這不壞。我會添加一些其他的想法。

  • 正如Thomas所示,您不需要中間變量標題日期和正文。嘗試雖然

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

    這是真的,你可以離開的字段名,但我有時像他們保持代碼的自我記錄。 (我覺得去獸醫喜歡他們。)

  • 我大驚小怪字符串與字節的片,但可能比我更應該。由於您正在一口氣閱讀文件,因此您可能不需要擔心這一點。將所有東西都轉換成一個大字符串,然後切分字符串是一種方便的方式,只要記住你將整個字符串固定在內存中,如果你保留它的任何部分。如果你的文件很大,或者你的文件很多,而你最終只能保留大部分文件的元數據,那麼這可能不是一條可行的路。

  • 每個文件只有一個博客條目?如果是這樣,我想我會提出一個托馬斯建議的變種。驗證第一個字節是---(或者你的文件已損壞),然後使用strings.Index(fileString [3:],「---」)。如果您有未知數量的細分受衆羣,分割更合適。在你的情況下,你只是在meta之後尋找那個單獨的分隔符。索引會在搜索完meta後找到它,而不用搜索整個身體。 (無論如何,如果身體包含字符串「---」?)

  • 最後,有些人會爲此使用正則表達式。我還沒有預熱到正則表達式,但無論如何,這是另一種方法。

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) 
} 
相關問題