func (p *Parser) Next() bool {
	if !p.keepRanges && p.rangeStart < p.rangeEnd {
		p.rangeStart++
		return true
	}
	p.comment = ""
	p.field = p.field[:0]
	p.parsedRange = false
	for p.scanner.Scan() && p.err == nil {
		p.line++
		s := p.scanner.Text()
		if s == "" {
			continue
		}
		if s[0] == '#' {
			if p.commentHandler != nil {
				p.commentHandler(strings.TrimSpace(s[1:]))
			}
			continue
		}
		if i := strings.IndexByte(s, '#'); i != -1 {
			p.comment = strings.TrimSpace(s[i+1:])
			s = s[:i]
		}
		if s[0] == '@' {
			if p.partHandler != nil {
				p.field = append(p.field, strings.TrimSpace(s[1:]))
				p.partHandler(p)
				p.field = p.field[:0]
			}
			p.comment = ""
			continue
		}
		for {
			i := strings.IndexByte(s, ';')
			if i == -1 {
				p.field = append(p.field, strings.TrimSpace(s))
				break
			}
			p.field = append(p.field, strings.TrimSpace(s[:i]))
			s = s[i+1:]
		}
		if !p.keepRanges {
			p.rangeStart, p.rangeEnd = p.getRange(0)
		}
		return true
	}
	p.setError(p.scanner.Err(), "scanner failed")
	return false
}
Next parses the next line in the file. It returns true if a line was parsed
and false if it reached the end of the file.
package ucd  
import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"log"
	"regexp"
	"strconv"
	"strings"
)
const (
	CodePoint = iota
	Name
	GeneralCategory
	CanonicalCombiningClass
	BidiClass
	DecompMapping
	DecimalValue
	DigitValue
	NumericValue
	BidiMirrored
	Unicode1Name
	ISOComment
	SimpleUppercaseMapping
	SimpleLowercaseMapping
	SimpleTitlecaseMapping
)
func Parse(r io.ReadCloser, f func(p *Parser)) {
	defer r.Close()
	p := New(r)
	for p.Next() {
		f(p)
	}
	if err := p.Err(); err != nil {
		r.Close()  
		log.Fatal(err)
	}
}
type Option func(p *Parser)
func keepRanges(p *Parser) {
	p.keepRanges = true
}
var (
	KeepRanges Option = keepRanges
)
func Part(f func(p *Parser)) Option {
	return func(p *Parser) {
		p.partHandler = f
	}
}
func CommentHandler(f func(s string)) Option {
	return func(p *Parser) {
		p.commentHandler = f
	}
}
type Parser struct {
	scanner *bufio.Scanner
	keepRanges bool  
	err     error
	comment string
	field   []string
	line                 int
	parsedRange          bool
	rangeStart, rangeEnd rune
	partHandler    func(p *Parser)
	commentHandler func(s string)
}
func (p *Parser) setError(err error, msg string) {
	if p.err == nil && err != nil {
		if msg == "" {
			p.err = fmt.Errorf("ucd:line:%d: %v", p.line, err)
		} else {
			p.err = fmt.Errorf("ucd:line:%d:%s: %v", p.line, msg, err)
		}
	}
}
func (p *Parser) getField(i int) string {
	if i >= len(p.field) {
		return ""
	}
	return p.field[i]
}
func (p *Parser) Err() error {
	return p.err
}
func New(r io.Reader, o ...Option) *Parser {
	p := &Parser{
		scanner: bufio.NewScanner(r),
	}
	for _, f := range o {
		f(p)
	}
	return p
}