【问题标题】:Strip consecutive empty lines in a golang writer在 golang writer 中去除连续的空行
【发布时间】:2015-02-05 20:21:13
【问题描述】:

我有一个呈现文件的 Go 文本/模板,但是我发现很难在保持输出中的换行符的同时清晰地构建模板。

我想在模板中添加额外的、不必要的换行符以使其更具可读性,但从输出中删除它们。任何多于普通段落分隔符的换行符组都应压缩为普通段落分隔符,例如

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)
    }
}

这不起作用,因为我天真地假设它会缓冲换行符,但事实并非如此。

关于如何让它工作的任何建议?

【问题讨论】:

  • 或许以此Play为起点:
  • ~100 MB 在非常小的服务器上。
  • 虽然我不明白为什么这对这个问题很重要,除非你要回答“不要”。
  • 请注意,您有一个值接收器,因此下一次 Write 调用将无法观察到 c.lastLineIsEmpty = thisLineIsEmpty

标签: go writer


【解决方案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

【讨论】:

  • 不错!尽管striplines.Striplines 是一个糟糕的类型名称(它会结结巴巴)。 striplines.Writerinstead 怎么样?
【解决方案2】:

一般的想法是,您必须在输入切片中的任何位置查找连续的换行符,如果存在这种情况,则跳过除第一个换行符之外的所有换行符。

此外,您必须跟踪写入的最后一个字节是否是换行符,因此下一次调用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")
}

【讨论】:

  • 你没有提到空格。 “任何超过正常段落分隔符的换行符都应该被压缩”
  • 虽然这将是一个简单的更新。无需与 Newline var 进行比较,只需检查任何空格。
猜你喜欢
  • 1970-01-01
  • 2016-08-17
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 2021-02-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多