gopkg.in/tools/godep.v67@v67.0.0-20160513230433-2d182dfe781d/Godeps/_workspace/src/github.com/kr/text/wrap.go (about) 1 package text 2 3 import ( 4 "bytes" 5 "math" 6 ) 7 8 var ( 9 nl = []byte{'\n'} 10 sp = []byte{' '} 11 ) 12 13 const defaultPenalty = 1e5 14 15 // Wrap wraps s into a paragraph of lines of length lim, with minimal 16 // raggedness. 17 func Wrap(s string, lim int) string { 18 return string(WrapBytes([]byte(s), lim)) 19 } 20 21 // WrapBytes wraps b into a paragraph of lines of length lim, with minimal 22 // raggedness. 23 func WrapBytes(b []byte, lim int) []byte { 24 words := bytes.Split(bytes.Replace(bytes.TrimSpace(b), nl, sp, -1), sp) 25 var lines [][]byte 26 for _, line := range WrapWords(words, 1, lim, defaultPenalty) { 27 lines = append(lines, bytes.Join(line, sp)) 28 } 29 return bytes.Join(lines, nl) 30 } 31 32 // WrapWords is the low-level line-breaking algorithm, useful if you need more 33 // control over the details of the text wrapping process. For most uses, either 34 // Wrap or WrapBytes will be sufficient and more convenient. 35 // 36 // WrapWords splits a list of words into lines with minimal "raggedness", 37 // treating each byte as one unit, accounting for spc units between adjacent 38 // words on each line, and attempting to limit lines to lim units. Raggedness 39 // is the total error over all lines, where error is the square of the 40 // difference of the length of the line and lim. Too-long lines (which only 41 // happen when a single word is longer than lim units) have pen penalty units 42 // added to the error. 43 func WrapWords(words [][]byte, spc, lim, pen int) [][][]byte { 44 n := len(words) 45 46 length := make([][]int, n) 47 for i := 0; i < n; i++ { 48 length[i] = make([]int, n) 49 length[i][i] = len(words[i]) 50 for j := i + 1; j < n; j++ { 51 length[i][j] = length[i][j-1] + spc + len(words[j]) 52 } 53 } 54 55 nbrk := make([]int, n) 56 cost := make([]int, n) 57 for i := range cost { 58 cost[i] = math.MaxInt32 59 } 60 for i := n - 1; i >= 0; i-- { 61 if length[i][n-1] <= lim { 62 cost[i] = 0 63 nbrk[i] = n 64 } else { 65 for j := i + 1; j < n; j++ { 66 d := lim - length[i][j-1] 67 c := d*d + cost[j] 68 if length[i][j-1] > lim { 69 c += pen // too-long lines get a worse penalty 70 } 71 if c < cost[i] { 72 cost[i] = c 73 nbrk[i] = j 74 } 75 } 76 } 77 } 78 79 var lines [][][]byte 80 i := 0 81 for i < n { 82 lines = append(lines, words[i:nbrk[i]]) 83 i = nbrk[i] 84 } 85 return lines 86 }