删除一个golang作家的连续空行
我有一个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)
}
}
这不工作,因为我天真地认为,这将缓冲的换行符,但事实并非如此。
有关如何使其发挥作用的任何建议?
总的想法是你必须在输入切片中的任何位置查找连续的换行符,如果存在这种情况,请跳过除第一个换行符外的所有换行符。
此外,您必须跟踪写入的最后一个字节是否为换行符,因此如果需要,下一个调用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")
}
通过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
不错!虽然'striplines.Striplines'是一个糟糕的类型名称(它结结巴巴)。 'striplines.Writer'代替了吗? – zmb 2015-02-13 23:39:00
也许用这个游戏作为一个起点: – Alex 2015-02-05 20:29:27
HTTP ://play.golang.org/p/wNtHFHobhm – Alex 2015-02-05 20:35:04
定义太大。 – 2015-02-05 20:41:18