github.com/searKing/golang/go@v1.2.117/io/counter.go (about) 1 package io 2 3 import ( 4 "bufio" 5 "bytes" 6 "io" 7 8 bytes_ "github.com/searKing/golang/go/bytes" 9 ) 10 11 // Count counts the number of non-overlapping instances of sep in r. 12 // If sep is an empty slice, Count returns 1 + the number of UTF-8-encoded code points in s. 13 // tailMatch returns true if tail bytes match sep 14 func Count(r io.Reader, sep string) (cnt int, tailMatch bool, err error) { 15 return CountSize(r, sep, bufio.MaxScanTokenSize) 16 } 17 18 // CountSize counts the number of non-overlapping instances of sep in r. 19 // tailMatch returns true if tail bytes match sep 20 func CountSize(r io.Reader, sep string, size int) (cnt int, tailMatch bool, err error) { 21 // special case 22 if len(sep) == 0 || len(sep) == 1 { 23 return CountAnySize(r, sep, size) 24 } 25 26 if size < len(sep) { 27 size = len(sep) 28 } 29 var count int 30 buf := make([]byte, size) 31 32 // buffered bytes 33 var bufferedPos int 34 for { 35 n, err := r.Read(buf[bufferedPos:]) 36 if n > 0 { 37 bufferedPos += n 38 cnt, index := bytes_.CountIndex(buf[:bufferedPos], []byte(sep)) 39 count += cnt 40 41 // store the next index to do match 42 var tailIndex int 43 if index >= 0 { 44 // skip matched 45 tailIndex = index + len(sep) 46 } else { 47 // skip first byte 48 tailIndex = 1 49 } 50 51 copyCnt := bufferedPos - tailIndex 52 if copyCnt >= len(sep) { 53 copyCnt = len(sep) - 1 54 } 55 56 // buffer tail bytes if any 57 if copyCnt > 0 { 58 copy(buf[:copyCnt], buf[tailIndex:tailIndex+copyCnt]) 59 bufferedPos = copyCnt 60 } else { 61 bufferedPos = 0 62 } 63 } 64 if err == io.EOF { 65 return count, bufferedPos == 0, nil 66 } 67 if err != nil { 68 return count, true, err 69 } 70 } 71 } 72 73 // CountAnySize counts the number of non-overlapping instances of sep in r. 74 // If sep is an empty slice, Count returns 1 + the number of UTF-8-encoded code points in s. 75 func CountAny(r io.Reader, sep string) (cnt int, tailMatch bool, err error) { 76 return CountAnySize(r, sep, bufio.MaxScanTokenSize) 77 } 78 79 // CountAnySize counts the number of non-overlapping instances of sep in r. 80 // If sep is an empty slice, Count returns 1 + the number of UTF-8-encoded code points in s. 81 func CountAnySize(r io.Reader, sep string, size int) (cnt int, tailMatch bool, err error) { 82 var count int 83 if size < 1 { 84 size = 1 85 } 86 87 buf := make([]byte, size) 88 var lastByte byte 89 for { 90 n, err := r.Read(buf) 91 if n > 0 { 92 lastByte = buf[n-1] 93 count += bytes.Count(buf[:n], []byte(sep)) 94 } 95 if err == io.EOF { 96 if bytes.ContainsAny([]byte(sep), string(lastByte)) { 97 return count, true, nil 98 } 99 return count, false, nil 100 } 101 if err != nil { 102 return count, true, err 103 } 104 } 105 } 106 107 // CountLines counts the number of lines by \n. 108 func CountLines(r io.Reader) (lines int, err error) { 109 return CountLinesSize(r, bufio.MaxScanTokenSize) 110 } 111 112 // CountLinesSize counts the number of lines by \n. 113 func CountLinesSize(r io.Reader, size int) (lines int, err error) { 114 cnt, tailMatch, err := CountSize(r, "\n", size) 115 // take care of ending line without '\n' 116 if !tailMatch { 117 cnt++ 118 } 119 return cnt, err 120 }