-
Notifications
You must be signed in to change notification settings - Fork 19
/
name_node.go
224 lines (177 loc) 路 5.15 KB
/
name_node.go
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
package gedcom
import (
"regexp"
"strings"
"unicode"
)
// NameNode represents all the parts that make up a single name. An individual
// may have more than one name, each one would be represented by a NameNode.
type NameNode struct {
*SimpleNode
}
func NewNameNode(document *Document, value, pointer string, children []Node) *NameNode {
return &NameNode{
newSimpleNode(document, TagName, value, pointer, children),
}
}
var nameRegexp = regexp.MustCompile("([^/]*)(/[^/]*/)?(.*)")
func (node *NameNode) parts() []string {
return nameRegexp.FindStringSubmatch(node.value)
}
// GivenName is the given or earned name used for official identification of a
// person. It is also commonly known as the "first name".
func (node *NameNode) GivenName() string {
if node == nil {
return ""
}
// GivenName is the proper first name.
givenNames := NodesWithTag(node, TagGivenName)
if len(givenNames) > 0 {
return CleanSpace(givenNames[0].Value())
}
// Fall back to trying to extract the first name from NAME tag.
return CleanSpace(node.parts()[1])
}
// Surname is a family name passed on or used by members of a family.
func (node *NameNode) Surname() string {
if node == nil {
return ""
}
// Surname is the proper last name.
surnames := NodesWithTag(node, TagSurname)
if len(surnames) > 0 {
return CleanSpace(surnames[0].Value())
}
// Fallback to trying to extract the surname from the NAME tag.
lastName := CleanSpace(node.parts()[2])
if lastName == "" {
return ""
}
// The surname (if provided) will be wrapped within //.
lastNameLength := len(lastName)
return lastName[1 : lastNameLength-1]
}
func (node *NameNode) Prefix() string {
if node == nil {
return ""
}
// NamePrefix is the proper name prefix. If it is not provided then no
// prefix should be returned.
namePrefixes := NodesWithTag(node, TagNamePrefix)
if len(namePrefixes) > 0 {
return CleanSpace(namePrefixes[0].Value())
}
return ""
}
func (node *NameNode) Suffix() string {
if node == nil {
return ""
}
// NameSuffix is the proper name suffix.
nameSuffixes := NodesWithTag(node, TagNameSuffix)
if len(nameSuffixes) > 0 {
return CleanSpace(nameSuffixes[0].Value())
}
// Otherwise fallback to trying to extract it from the NAME.
return CleanSpace(node.parts()[3])
}
func (node *NameNode) SurnamePrefix() string {
if node == nil {
return ""
}
// SurnameSuffix is the proper surname prefix.
surnamePrefixes := NodesWithTag(node, TagSurnamePrefix)
if len(surnamePrefixes) > 0 {
return CleanSpace(surnamePrefixes[0].Value())
}
// Otherwise return nothing.
return ""
}
func (node *NameNode) Title() string {
if node == nil {
return ""
}
// Title is the proper individual title.
titles := NodesWithTag(node, TagTitle)
if len(titles) > 0 {
return CleanSpace(titles[0].Value())
}
// Otherwise return nothing.
return ""
}
// String returns all name components in the format that would be written like
// "Grand Duke Bob Smith Esq.". It specifically uses NameFormatWritten.
func (node *NameNode) String() string {
return node.Format(NameFormatWritten)
}
func (node *NameNode) Type() NameType {
if node == nil {
return NameTypeNormal
}
if nameType := First(NodesWithTag(node, TagType)); nameType != nil {
return NameType(nameType.Value())
}
// Otherwise return nothing.
return NameTypeNormal
}
// GedcomName returns the simplified GEDCOM name often used also as the value
// for the NAME node.
//
// The only difference between this as String() is that the surname is
// encapsulated inside forward slashes like:
//
// Sir Elliot Rupert /Chance/ Sr
//
// Even this uses the NameFormatGEDCOM it may return a different value from
// Format(NameFormatGEDCOM) because any empty surnames will be removed.
func (node *NameNode) GedcomName() (name string) {
name = node.Format(NameFormatGEDCOM)
name = strings.Replace(name, "//", "", -1)
name = CleanSpace(name)
return
}
// Format returns a formatted name.
//
// There are some common formats described with the NameFormat constants. See
// NameFormat for a full description.
func (node *NameNode) Format(format NameFormat) string {
result := ""
formatLen := len(format)
for i := 0; i < formatLen; i++ {
if format[i] == '%' && i < formatLen-1 {
nextLetter := format[i+1]
switch nextLetter {
case '%':
result += "%"
case 'f', 'F':
result += renderNameComponent(nextLetter, node.GivenName())
case 'l', 'L':
result += renderNameComponent(nextLetter, node.Surname())
case 'm', 'M':
result += renderNameComponent(nextLetter, node.SurnamePrefix())
case 'p', 'P':
result += renderNameComponent(nextLetter, node.Prefix())
case 's', 'S':
result += renderNameComponent(nextLetter, node.Suffix())
case 't', 'T':
result += renderNameComponent(nextLetter, node.Title())
default:
result += "%" + string(nextLetter)
}
i++
} else {
result += string(format[i])
}
}
return CleanSpace(result)
}
func renderNameComponent(letter byte, namePart string) string {
isUpper := unicode.IsUpper(rune(letter))
return conditionalUpperCase(namePart, isUpper)
}
func conditionalUpperCase(s string, upperCase bool) string {
if upperCase {
return strings.ToUpper(s)
}
return s
}