2015-02-05 39 views
0

我有一個Go文本/模板來渲染一個文件,但是我發現很難在保留輸出中的換行符的同時乾淨地構造模板。刪除一個golang作家的連續空行

我想在模板中增加額外的不必要的換行符,使其更具可讀性,但將它們從輸出中去除。任何比正常段落中斷更多的換行符都應該縮寫爲正常的段落中斷,例如,

lines with 



too many breaks should become lines with 

normal paragraph breaks. 

字符串可能太大而不能安全地存儲在內存中,所以我想保留它作爲輸出流。

我第一次嘗試:

type condensingWriter struct { 
    writer io.Writer 
    lastLineIsEmpty bool 
} 

func (c condensingWriter) Write(b []byte) (n int, err error){ 
    thisLineIsEmpty := strings.TrimSpace(string(b)) == "" 
    defer func(){ 
     c.lastLineIsEmpty = thisLineIsEmpty 
    }() 
    if c.lastLineIsEmpty && thisLineIsEmpty{ 
     return 0, nil 
    } else { 
     return c.writer.Write(b) 
    } 
} 

這不工作,因爲我天真地認爲,這將緩衝的換行符,但事實並非如此。

有關如何使其發揮作用的任何建議?

+0

也許用這個遊戲作爲一個起點: – Alex 2015-02-05 20:29:27

+0

HTTP ://play.golang.org/p/wNtHFHobhm – Alex 2015-02-05 20:35:04

+0

定義太大。 – 2015-02-05 20:41:18

回答

0

總的想法是你必須在輸入切片中的任何位置查找連續的換行符,如果存在這種情況,請跳過除第一個換行符外的所有換行符。

此外,您必須跟蹤寫入的最後一個字節是否爲換行符,因此如果需要,下一個調用Write將知道消除換行符。您在編輯器類型中添加了bool,這是正確的。但是,您會希望在此處使用指針接收器而不是值接收器,否則您將修改結構的副本

你想改變

func (c condensingWriter) Write(b []byte) 

func (c *condensingWriter) Write(b []byte) 

你可以嘗試像this東西。你必須測試更大的輸入,以確保它能正確處理所有情況。

package main 

import (
    "bytes" 
    "io" 
    "os" 
) 

var Newline byte = byte('\n') 

type ReduceNewlinesWriter struct { 
    w    io.Writer 
    lastByteNewline bool 
} 

func (r *ReduceNewlinesWriter) Write(b []byte) (int, error) { 
    // if the previous call to Write ended with a \n 
    // then we have to skip over any starting newlines here 
    i := 0 
    if r.lastByteNewline { 
     for i < len(b) && b[i] == Newline { 
      i++ 
     } 
     b = b[i:] 
    } 
    r.lastByteNewline = b[len(b) - 1] == Newline 

    i = bytes.IndexByte(b, Newline) 
    if i == -1 { 
     // no newlines - just write the entire thing 
     return r.w.Write(b) 
    } 
    // write up to the newline 
    i++ 
    n, err := r.w.Write(b[:i]) 
    if err != nil { 
     return n, err 
    } 

    // skip over immediate newline and recurse 
    i++ 

    for i < len(b) && b[i] == Newline { 
     i++ 
    } 
    i-- 
    m, err := r.Write(b[i:]) 
    return n + m, nil 
} 

func main() { 
    r := ReduceNewlinesWriter{ 
     w: os.Stdout, 
    } 
    io.WriteString(&r, "this\n\n\n\n\n\n\nhas\nmultiple\n\n\nnewline\n\n\n\ncharacters") 
} 
+0

我不認爲這適用於由空格分隔的換行符? – Alex 2015-02-06 21:47:29

+0

你沒有說空間的任何事情。 「任何一組換行比正常段落都要精簡」 – zmb 2015-02-06 21:52:39

+0

雖然這將是一個簡單的更新。而不是與Newline var進行比較,只需檢查任何空格。 – zmb 2015-02-06 21:53:35

1

通過ZMB的做法的啓發,我想出了下面的包:

//Package striplines strips runs of consecutive empty lines from an output stream. 
package striplines 

import (
    "io" 
    "strings" 
) 

// Striplines wraps an output stream, stripping runs of consecutive empty lines. 
// You must call Flush before the output stream will be complete. 
// Implements io.WriteCloser, Writer, Closer. 
type Striplines struct { 
    Writer io.Writer 
    lastLine []byte 
    currentLine []byte 
} 

func (w *Striplines) Write(p []byte) (int, error) { 
    totalN := 0 
    s := string(p) 
    if !strings.Contains(s, "\n") { 
    w.currentLine = append(w.currentLine, p...) 
    return 0, nil 
    } 
    cur := string(append(w.currentLine, p...)) 
    lastN := strings.LastIndex(cur, "\n") 
    s = cur[:lastN] 
    for _, line := range strings.Split(s, "\n") { 
    n, err := w.writeLn(line + "\n") 
    w.lastLine = []byte(line) 
    if err != nil { 
     return totalN, err 
    } 
    totalN += n 
    } 
    rem := cur[(lastN + 1):] 
    w.currentLine = []byte(rem) 
    return totalN, nil 
} 

// Close flushes the last of the output into the underlying writer. 
func (w *Striplines) Close() error { 
    _, err := w.writeLn(string(w.currentLine)) 
    return err 
} 

func (w *Striplines) writeLn(line string) (n int, err error) { 
    if strings.TrimSpace(string(w.lastLine)) == "" && strings.TrimSpace(line) == "" { 
    return 0, nil 
    } else { 
    return w.Writer.Write([]byte(line)) 
    } 
} 

看到它在這裏的行動:http://play.golang.org/p/t8BGPUMYhb

+0

不錯!雖然'striplines.Striplines'是一個糟糕的類型名稱(它結結巴巴)。 'striplines.Writer'代替了嗎? – zmb 2015-02-13 23:39:00