aboutsummaryrefslogtreecommitdiff
path: root/src/urubu/ucd/unicode_data.go
blob: e2a8e87581e25016db6fdbe1a3bf2e76ca675418 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package ucd

import "io"

type UnicodeData struct {
	GeneralCategory map[string][]*CodePointRange

	propValAliases *PropertyValueAliases
}

// ParseUnicodeData parses the UnicodeData.txt.
func ParseUnicodeData(r io.Reader, propValAliases *PropertyValueAliases) (*UnicodeData, error) {
	unicodeData := &UnicodeData{
		GeneralCategory: map[string][]*CodePointRange{},
		propValAliases:  propValAliases,
	}

	p := newParser(r)
	for p.parse() {
		if len(p.fields) == 0 {
			continue
		}
		cp, err := p.fields[0].codePointRange()
		if err != nil {
			return nil, err
		}
		gc := p.fields[2].normalizedSymbol()
		unicodeData.addGC(gc, cp)
	}
	if p.err != nil {
		return nil, p.err
	}

	return unicodeData, nil
}

func (u *UnicodeData) addGC(gc string, cp *CodePointRange) {
	// https://www.unicode.org/reports/tr44/#Empty_Fields
	// > The data file UnicodeData.txt defines many property values in each record. When a field in a data line
	// > for a code point is empty, that indicates that the property takes the default value for that code point.
	if gc == "" {
		return
	}

	cps, ok := u.GeneralCategory[u.propValAliases.gcAbb(gc)]
	if ok {
		c := cps[len(cps)-1]
		if cp.From-c.To == 1 {
			c.To = cp.To
		} else {
			u.GeneralCategory[u.propValAliases.gcAbb(gc)] = append(cps, cp)
		}
	} else {
		u.GeneralCategory[u.propValAliases.gcAbb(gc)] = []*CodePointRange{cp}
	}
}