func NewMappedStringReader(r StringReader, mapFn func(string) string) *MappedStringReader {
	return &MappedStringReader{r:r, mapFn: mapFn}
}
NewMappedStringReader creates a new MappedStringReader that reads strings from
r and can call mapFn for transforming the string before returning it.
package utils
import (
	"bufio"
	"io"
	"os"
	"regexp"
	"strings"
)
type StringReader interface {
	ReadString() (string, error)
}
type StringArrayReader struct {
	strings []string
	pos     int
}
func NewStringArrayReader(strings []string) *StringArrayReader {
	return &StringArrayReader{strings: strings}
}
func (sar *StringArrayReader) ReadString() (string, error) {
	if sar.pos == len(sar.strings) {
		return "", io.EOF
	}
	s := sar.strings[sar.pos]
	sar.pos++
	return s, nil
}
type StringIOReader struct {
	scanner *bufio.Scanner
}
func NewStringIOReader(r io.Reader) *StringIOReader {
	return &StringIOReader{scanner: bufio.NewScanner(r)}
}
func (sir *StringIOReader) ReadString() (string, error) {
	for sir.scanner.Scan() {
		s := strings.TrimSpace(sir.scanner.Text())
		if s != "" {
			return s, nil
		}
	}
	return "", io.EOF
}
type FilteredStringReader struct {
	r  StringReader
	re *regexp.Regexp
}
func NewFilteredStringReader(r StringReader, re *regexp.Regexp) *FilteredStringReader {
	return &FilteredStringReader{r: r, re: re}
}
func (f *FilteredStringReader) ReadString() (s string, err error) {
	for s, err = f.r.ReadString(); s != "" || err == nil; s, err = f.r.ReadString() {
		if f.re.MatchString(s) {
			return s, err
		}
	}
	return s, err
}
type MappedStringReader struct {
	r StringReader
	mapFn func(string) string
}