name_tamer 0.6.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +76 -0
- data/LICENSE +1 -1
- data/README.md +60 -33
- data/lib/name_tamer/constants/adfixes_prefix_person +44 -0
- data/lib/name_tamer/constants/adfixes_suffix_organization +213 -0
- data/lib/name_tamer/constants/adfixes_suffix_person +131 -0
- data/lib/name_tamer/constants.rb +17 -402
- data/lib/name_tamer/name/private_methods_nice_name.rb +116 -0
- data/lib/name_tamer/name/private_methods_simple_name.rb +71 -0
- data/lib/name_tamer/name/utilities.rb +84 -0
- data/lib/name_tamer/name.rb +11 -294
- data/lib/name_tamer/strings/approximations.rb +209 -0
- data/lib/name_tamer/strings/bad_encoding.rb +148 -0
- data/lib/name_tamer/strings/capitalization.rb +46 -0
- data/lib/name_tamer/strings/compound_names.rb +34 -0
- data/lib/name_tamer/strings/core.rb +62 -0
- data/lib/name_tamer/strings/name_modifiers.rb +51 -0
- data/lib/name_tamer/strings/spacing.rb +22 -0
- data/lib/name_tamer/strings.rb +9 -0
- data/lib/name_tamer/text.rb +18 -12
- data/lib/name_tamer/version.rb +1 -1
- data/lib/name_tamer.rb +1 -2
- metadata +25 -25
- data/.codeclimate.yml +0 -18
- data/.env +0 -1
- data/.gitignore +0 -27
- data/.hound.yml +0 -6
- data/.rspec +0 -2
- data/.rubocop.yml +0 -61
- data/.travis.yml +0 -11
- data/Gemfile +0 -26
- data/Guardfile +0 -18
- data/Rakefile +0 -16
- data/doc/maintenance.rake +0 -76
- data/doc/prefixes.csv +0 -49
- data/doc/suffixes.csv +0 -345
- data/lib/name_tamer/array.rb +0 -8
- data/lib/name_tamer/string.rb +0 -563
- data/name_tamer.gemspec +0 -20
data/lib/name_tamer/constants.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module NameTamer
|
|
4
4
|
NONBREAKING_SPACE = "\u00a0"
|
|
5
5
|
ASCII_SPACE = ' '
|
|
6
|
-
ADFIX_JOINERS = "[#{ASCII_SPACE}-]"
|
|
6
|
+
ADFIX_JOINERS = "[#{ASCII_SPACE}-]".freeze
|
|
7
7
|
SLUG_DELIMITER = '-'
|
|
8
8
|
ZERO_WIDTH_FILTER = /[\u180E\u200B\u200C\u200D\u2063\uFEFF]/
|
|
9
9
|
|
|
@@ -39,9 +39,9 @@ module NameTamer
|
|
|
39
39
|
ALPHA = 'A-Za-z'
|
|
40
40
|
DIGIT = '0-9'
|
|
41
41
|
UCSCHAR = '\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF'
|
|
42
|
-
IUNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~#{UCSCHAR}"
|
|
42
|
+
IUNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~#{UCSCHAR}".freeze
|
|
43
43
|
SUBDELIMS = '!$&\'\(\)\*+,;='
|
|
44
|
-
ISEGMENT_NZ_NC = "#{IUNRESERVED}#{SUBDELIMS}@" # pct-encoded not needed
|
|
44
|
+
ISEGMENT_NZ_NC = "#{IUNRESERVED}#{SUBDELIMS}@".freeze # pct-encoded not needed
|
|
45
45
|
FILTER_RFC3987 = /[^#{ISEGMENT_NZ_NC}]/
|
|
46
46
|
FILTER_COMPAT = /[^#{ALPHA}#{DIGIT}\-_#{UCSCHAR}]/
|
|
47
47
|
|
|
@@ -49,54 +49,14 @@ module NameTamer
|
|
|
49
49
|
# If you add to the list, you can use spaces and dots where appropriate
|
|
50
50
|
# Ensure any single letters are followed by a dot because we'll add one to the string
|
|
51
51
|
# during processing, e.g. "y Cia." should be "y. Cia."
|
|
52
|
+
|
|
53
|
+
private_class_method def self.get_constants_from(filename)
|
|
54
|
+
File.readlines(Pathname.new(__dir__).join('constants', filename), chomp: true).reject(&:empty?)
|
|
55
|
+
end
|
|
56
|
+
|
|
52
57
|
ADFIXES = {
|
|
53
58
|
prefix: {
|
|
54
|
-
person:
|
|
55
|
-
'Baroness',
|
|
56
|
-
'Capt.',
|
|
57
|
-
'Captain',
|
|
58
|
-
'Col.',
|
|
59
|
-
'Colonel',
|
|
60
|
-
'Dame',
|
|
61
|
-
'Doctor',
|
|
62
|
-
'Doktor',
|
|
63
|
-
'Dr.',
|
|
64
|
-
'Frau',
|
|
65
|
-
'Herr',
|
|
66
|
-
'Judge',
|
|
67
|
-
'Justice',
|
|
68
|
-
'Lady',
|
|
69
|
-
'Lieut.',
|
|
70
|
-
'Lieutenant',
|
|
71
|
-
'Lord',
|
|
72
|
-
'Madame',
|
|
73
|
-
'Major',
|
|
74
|
-
'Master',
|
|
75
|
-
'Matron',
|
|
76
|
-
'Messrs.',
|
|
77
|
-
'Mgr.',
|
|
78
|
-
'Miss',
|
|
79
|
-
'Mister',
|
|
80
|
-
'Mlle.',
|
|
81
|
-
'Mme.',
|
|
82
|
-
'Mons.',
|
|
83
|
-
'Mr. & Mrs.',
|
|
84
|
-
'Mr. and Mrs.',
|
|
85
|
-
'Mr.',
|
|
86
|
-
'Mrs.',
|
|
87
|
-
'Ms.',
|
|
88
|
-
'Msgr.',
|
|
89
|
-
'Prof.',
|
|
90
|
-
'Professor',
|
|
91
|
-
'Rev.',
|
|
92
|
-
'Reverend',
|
|
93
|
-
'Sir',
|
|
94
|
-
'Sister',
|
|
95
|
-
'The Hon.',
|
|
96
|
-
'The Lady.',
|
|
97
|
-
'The Lord',
|
|
98
|
-
'The Rt. Hon.',
|
|
99
|
-
],
|
|
59
|
+
person: get_constants_from('adfixes_prefix_person'),
|
|
100
60
|
organization: [
|
|
101
61
|
'Fa.',
|
|
102
62
|
'P.T. Tbk.',
|
|
@@ -106,369 +66,24 @@ module NameTamer
|
|
|
106
66
|
before: '\\A', after: ADFIX_JOINERS
|
|
107
67
|
},
|
|
108
68
|
suffix: {
|
|
109
|
-
person:
|
|
110
|
-
|
|
111
|
-
'A.C.A.',
|
|
112
|
-
'A.C.C.',
|
|
113
|
-
'A.C.C.A.',
|
|
114
|
-
'A.C.M.A.',
|
|
115
|
-
'A.E.P.',
|
|
116
|
-
'A.I.F.',
|
|
117
|
-
'A.I.F.A.',
|
|
118
|
-
'A.S.A.',
|
|
119
|
-
'A.W.M.A.',
|
|
120
|
-
'B.A.',
|
|
121
|
-
'B.Ed.',
|
|
122
|
-
'B.Eng.',
|
|
123
|
-
'B.Sc.',
|
|
124
|
-
'B.Tech.',
|
|
125
|
-
'C.A.',
|
|
126
|
-
'C.A.I.A.',
|
|
127
|
-
'C.A.P.M.',
|
|
128
|
-
'C.B.V.',
|
|
129
|
-
'C.C.I.M.',
|
|
130
|
-
'C.D.F.A.',
|
|
131
|
-
'C.E.M.',
|
|
132
|
-
'C.E.P.P.',
|
|
133
|
-
'C.Eng.',
|
|
134
|
-
'C.F.A.',
|
|
135
|
-
'C.F.B.S.',
|
|
136
|
-
'C.F.F.',
|
|
137
|
-
'C.F.P.',
|
|
138
|
-
'C.F.S.',
|
|
139
|
-
'C.G.A.',
|
|
140
|
-
'C.G.B.',
|
|
141
|
-
'C.G.M.A.',
|
|
142
|
-
'C.G.P.',
|
|
143
|
-
'C.I.M.',
|
|
144
|
-
'C.I.S.S.P.',
|
|
145
|
-
'C.I.T.P.',
|
|
146
|
-
'C.L.P.',
|
|
147
|
-
'C.L.T.C.',
|
|
148
|
-
'C.L.U.',
|
|
149
|
-
'C.M.A.',
|
|
150
|
-
'C.M.T.',
|
|
151
|
-
'C.P.A.',
|
|
152
|
-
'C.P.C.C.',
|
|
153
|
-
'C.R.P.C.',
|
|
154
|
-
'C.R.P.S.',
|
|
155
|
-
'C.S.O.X.',
|
|
156
|
-
'C.S.S.D.',
|
|
157
|
-
'C.T.A.',
|
|
158
|
-
'C.W.S.',
|
|
159
|
-
'Cantab.',
|
|
160
|
-
'Ch.F.C.',
|
|
161
|
-
'Chartered F.C.S.I.',
|
|
162
|
-
'Chartered M.C.S.I.',
|
|
163
|
-
'D.B.E.',
|
|
164
|
-
'D.D.S.',
|
|
165
|
-
'D.Phil.',
|
|
166
|
-
'D.V.M.',
|
|
167
|
-
'Dip. D.M.',
|
|
168
|
-
'E.A.',
|
|
169
|
-
'E.R.P.',
|
|
170
|
-
'Ed.D.',
|
|
171
|
-
'Ed.M.',
|
|
172
|
-
'Eng.D.',
|
|
173
|
-
'Esq.',
|
|
174
|
-
'F.B.C.S.',
|
|
175
|
-
'F.C.A.',
|
|
176
|
-
'F.C.C.A.',
|
|
177
|
-
'F.C.I.P.S.',
|
|
178
|
-
'F.C.M.I.',
|
|
179
|
-
'F.C.S.I.',
|
|
180
|
-
'F.I.E.T.',
|
|
181
|
-
'F.I.R.P.',
|
|
182
|
-
'F.Inst.L.M.',
|
|
183
|
-
'F.P.C.',
|
|
184
|
-
'F.R.M.',
|
|
185
|
-
'F.R.M.',
|
|
186
|
-
'G.S.P.',
|
|
187
|
-
'Hons.',
|
|
188
|
-
'I.F.R.S. Certified',
|
|
189
|
-
'I.T.I.L. v3',
|
|
190
|
-
'II',
|
|
191
|
-
'III',
|
|
192
|
-
'IV',
|
|
193
|
-
'J.D.',
|
|
194
|
-
'Jr.',
|
|
195
|
-
'K.C.',
|
|
196
|
-
'L.P.S.',
|
|
197
|
-
'LL.B.',
|
|
198
|
-
'LL.D.',
|
|
199
|
-
'LL.M.',
|
|
200
|
-
'M.A.',
|
|
201
|
-
'M.B.A.',
|
|
202
|
-
'M.B.E.',
|
|
203
|
-
'M.D.',
|
|
204
|
-
'M.E.P.',
|
|
205
|
-
'M.Ed.',
|
|
206
|
-
'M.Eng.',
|
|
207
|
-
'M.I.E.T.',
|
|
208
|
-
'M.Io.D.',
|
|
209
|
-
'M.Jur.',
|
|
210
|
-
'M.P.',
|
|
211
|
-
'M.P.A.',
|
|
212
|
-
'M.R.I.C.S.',
|
|
213
|
-
'M.S.',
|
|
214
|
-
'M.S.F.',
|
|
215
|
-
'M.S.F.S.',
|
|
216
|
-
'M.S.P.',
|
|
217
|
-
'M.Sc. D.',
|
|
218
|
-
'M.Sc.',
|
|
219
|
-
'O.B.E.',
|
|
220
|
-
'O.K.',
|
|
221
|
-
'O.R.S.C.',
|
|
222
|
-
'Oxon.',
|
|
223
|
-
'P.A.',
|
|
224
|
-
'P.C.C.',
|
|
225
|
-
'P.F.S.',
|
|
226
|
-
'P.H.R.',
|
|
227
|
-
'P.M.C.',
|
|
228
|
-
'P.M.P.',
|
|
229
|
-
'P.M.P.',
|
|
230
|
-
'P.S.P.',
|
|
231
|
-
'Ph.D.',
|
|
232
|
-
'Q.C.',
|
|
233
|
-
'R.D.',
|
|
234
|
-
'R.F.C.',
|
|
235
|
-
'R.I.C.P.',
|
|
236
|
-
'S.C.M.P',
|
|
237
|
-
'Sr.',
|
|
238
|
-
'T.M.I.E.T.',
|
|
239
|
-
'V',
|
|
240
|
-
'V.M.D.',
|
|
241
|
-
],
|
|
242
|
-
organization: [
|
|
243
|
-
# These are sorted in length order: don't alphabetize them.
|
|
244
|
-
'S. de R.L. de C.V.',
|
|
245
|
-
'S.A.P.I. de C.V.',
|
|
246
|
-
'y. Cía. S. en C.',
|
|
247
|
-
'Private Limited',
|
|
248
|
-
'S.M. Pte. Ltd.',
|
|
249
|
-
'Cía. S. C. A.',
|
|
250
|
-
'y. Cía. S. C.',
|
|
251
|
-
'S.A. de C.V.',
|
|
252
|
-
'spol. s.r.o.',
|
|
253
|
-
'(Pty.) Ltd.',
|
|
254
|
-
'(Pvt.) Ltd.',
|
|
255
|
-
'A.D.S.I.Tz.',
|
|
256
|
-
'S.p. z.o.o.',
|
|
257
|
-
'(Pvt.)Ltd.',
|
|
258
|
-
'akc. spol.',
|
|
259
|
-
'Cía. Ltda.',
|
|
260
|
-
'E.B.V.B.A.',
|
|
261
|
-
'P. Limited',
|
|
262
|
-
'S. de R.L.',
|
|
263
|
-
'S.I.C.A.V.',
|
|
264
|
-
'S.P.R.L.U.',
|
|
265
|
-
'А.Д.С.И.Ц.',
|
|
266
|
-
'(P.) Ltd.',
|
|
267
|
-
'C. por A.',
|
|
268
|
-
'Comm.V.A.',
|
|
269
|
-
'Ltd. Şti.',
|
|
270
|
-
'Plc. Ltd.',
|
|
271
|
-
'Pte. Ltd.',
|
|
272
|
-
'Pty. Ltd.',
|
|
273
|
-
'Pvt. Ltd.',
|
|
274
|
-
'Soc. Col.',
|
|
275
|
-
'A.M.B.A.',
|
|
276
|
-
'A.S.B.L.',
|
|
277
|
-
'A.V.E.E.',
|
|
278
|
-
'B.V.B.A.',
|
|
279
|
-
'B.V.I.O.',
|
|
280
|
-
'C.V.B.A.',
|
|
281
|
-
'C.V.O.A.',
|
|
282
|
-
'E.E.I.G.',
|
|
283
|
-
'E.I.R.L.',
|
|
284
|
-
'E.O.O.D.',
|
|
285
|
-
'E.U.R.L.',
|
|
286
|
-
'F.M.B.A.',
|
|
287
|
-
'G.m.b.H.',
|
|
288
|
-
'Ges.b.R.',
|
|
289
|
-
'K.G.a.A.',
|
|
290
|
-
'L.L.L.P.',
|
|
291
|
-
'Ltd. Co.',
|
|
292
|
-
'Ltd. Co.',
|
|
293
|
-
'M.E.P.E.',
|
|
294
|
-
'n.y.r.t.',
|
|
295
|
-
'O.V.E.E.',
|
|
296
|
-
'P.E.E.C.',
|
|
297
|
-
'P.L.L.C.',
|
|
298
|
-
'P.L.L.C.',
|
|
299
|
-
'S. en C.',
|
|
300
|
-
'S.a.p.a.',
|
|
301
|
-
'S.A.R.L.',
|
|
302
|
-
'S.à.R.L.',
|
|
303
|
-
'S.A.S.U.',
|
|
304
|
-
'S.C.e.I.',
|
|
305
|
-
'S.C.O.P.',
|
|
306
|
-
'S.C.p.A.',
|
|
307
|
-
'S.C.R.I.',
|
|
308
|
-
'S.C.R.L.',
|
|
309
|
-
'S.M.B.A.',
|
|
310
|
-
'S.P.R.L.',
|
|
311
|
-
'Е.О.О.Д.',
|
|
312
|
-
'&. Cie.',
|
|
313
|
-
'and Co.',
|
|
314
|
-
'Comm.V.',
|
|
315
|
-
'Limited',
|
|
316
|
-
'P. Ltd.',
|
|
317
|
-
'Part.G.',
|
|
318
|
-
'Sh.p.k.',
|
|
319
|
-
'&. Co.',
|
|
320
|
-
'C.X.A.',
|
|
321
|
-
'd.n.o.',
|
|
322
|
-
'd.o.o.',
|
|
323
|
-
'E.A.D.',
|
|
324
|
-
'e.h.f.',
|
|
325
|
-
'E.P.E.',
|
|
326
|
-
'E.S.V.',
|
|
327
|
-
'F.C.P.',
|
|
328
|
-
'F.I.E.',
|
|
329
|
-
'G.b.R.',
|
|
330
|
-
'G.I.E.',
|
|
331
|
-
'G.M.K.',
|
|
332
|
-
'G.S.K.',
|
|
333
|
-
'H.U.F.',
|
|
334
|
-
'K.D.A.',
|
|
335
|
-
'k.f.t.',
|
|
336
|
-
'k.h.t.',
|
|
337
|
-
'k.k.t.',
|
|
338
|
-
'L.L.C.',
|
|
339
|
-
'L.L.P.',
|
|
340
|
-
'o.h.f.',
|
|
341
|
-
'O.H.G.',
|
|
342
|
-
'O.O.D.',
|
|
343
|
-
'O.y.j.',
|
|
344
|
-
'p.l.c.',
|
|
345
|
-
'P.S.U.',
|
|
346
|
-
'S.A.E.',
|
|
347
|
-
'S.A.S.',
|
|
348
|
-
'S.C.A.',
|
|
349
|
-
'S.C.E.',
|
|
350
|
-
'S.C.S.',
|
|
351
|
-
'S.E.M.',
|
|
352
|
-
'S.E.P.',
|
|
353
|
-
's.e.s.',
|
|
354
|
-
'S.G.R.',
|
|
355
|
-
'S.N.C.',
|
|
356
|
-
'S.p.A.',
|
|
357
|
-
'S.P.E.',
|
|
358
|
-
'S.R.L.',
|
|
359
|
-
's.r.o.',
|
|
360
|
-
'Unltd.',
|
|
361
|
-
'V.O.F.',
|
|
362
|
-
'V.o.G.',
|
|
363
|
-
'v.o.s.',
|
|
364
|
-
'V.Z.W.',
|
|
365
|
-
'z.r.t.',
|
|
366
|
-
'А.А.Т.',
|
|
367
|
-
'Е.А.Д.',
|
|
368
|
-
'З.А.Т.',
|
|
369
|
-
'К.Д.А.',
|
|
370
|
-
'О.О.Д.',
|
|
371
|
-
'Т.А.А.',
|
|
372
|
-
'股份有限公司',
|
|
373
|
-
'Ap.S.',
|
|
374
|
-
'Corp.',
|
|
375
|
-
'ltda.',
|
|
376
|
-
'Sh.A.',
|
|
377
|
-
'st.G.',
|
|
378
|
-
'Ultd.',
|
|
379
|
-
'a.b.',
|
|
380
|
-
'A.D.',
|
|
381
|
-
'A.E.',
|
|
382
|
-
'A.G.',
|
|
383
|
-
'A.S.',
|
|
384
|
-
'A.Ş.',
|
|
385
|
-
'A.y.',
|
|
386
|
-
'B.M.',
|
|
387
|
-
'b.t.',
|
|
388
|
-
'B.V.',
|
|
389
|
-
'C.A.',
|
|
390
|
-
'C.V.',
|
|
391
|
-
'd.d.',
|
|
392
|
-
'e.c.',
|
|
393
|
-
'E.E.',
|
|
394
|
-
'e.G.',
|
|
395
|
-
'E.I.',
|
|
396
|
-
'E.P.',
|
|
397
|
-
'E.T.',
|
|
398
|
-
'E.U.',
|
|
399
|
-
'e.v.',
|
|
400
|
-
'G.K.',
|
|
401
|
-
'G.P.',
|
|
402
|
-
'h.f.',
|
|
403
|
-
'Inc.',
|
|
404
|
-
'K.D.',
|
|
405
|
-
'K.G.',
|
|
406
|
-
'K.K.',
|
|
407
|
-
'k.s.',
|
|
408
|
-
'k.v.',
|
|
409
|
-
'K.y.',
|
|
410
|
-
'L.C.',
|
|
411
|
-
'L.P.',
|
|
412
|
-
'Ltd.',
|
|
413
|
-
'N.K.',
|
|
414
|
-
'N.L.',
|
|
415
|
-
'N.V.',
|
|
416
|
-
'O.E.',
|
|
417
|
-
'O.G.',
|
|
418
|
-
'O.Ü.',
|
|
419
|
-
'O.y.',
|
|
420
|
-
'P.C.',
|
|
421
|
-
'p.l.',
|
|
422
|
-
'Pty.',
|
|
423
|
-
'PUP.',
|
|
424
|
-
'Pvt.',
|
|
425
|
-
'r.t.',
|
|
426
|
-
'S.A.',
|
|
427
|
-
'S.D.',
|
|
428
|
-
'S.E.',
|
|
429
|
-
's.f.',
|
|
430
|
-
'S.L.',
|
|
431
|
-
'S.P.',
|
|
432
|
-
'S.s.',
|
|
433
|
-
'T.K.',
|
|
434
|
-
'T.Ü.',
|
|
435
|
-
'U.Ü.',
|
|
436
|
-
'Y.K.',
|
|
437
|
-
'А.Д.',
|
|
438
|
-
'І.П.',
|
|
439
|
-
'К.Д.',
|
|
440
|
-
'ПУП.',
|
|
441
|
-
'С.Д.',
|
|
442
|
-
'בע"מ',
|
|
443
|
-
'任意組合',
|
|
444
|
-
'匿名組合',
|
|
445
|
-
'合同会社',
|
|
446
|
-
'合名会社',
|
|
447
|
-
'合資会社',
|
|
448
|
-
'有限会社',
|
|
449
|
-
'有限公司',
|
|
450
|
-
'株式会社',
|
|
451
|
-
'A/S',
|
|
452
|
-
'G/S',
|
|
453
|
-
'I/S',
|
|
454
|
-
'K/S',
|
|
455
|
-
'P/S',
|
|
456
|
-
'S/A',
|
|
457
|
-
],
|
|
69
|
+
person: get_constants_from('adfixes_suffix_person'),
|
|
70
|
+
organization: get_constants_from('adfixes_suffix_organization'),
|
|
458
71
|
before: ADFIX_JOINERS, after: '\\z'
|
|
459
72
|
},
|
|
460
73
|
}.freeze
|
|
461
74
|
|
|
462
|
-
|
|
75
|
+
CONTACT_TYPES = %i[person organization].freeze
|
|
76
|
+
|
|
77
|
+
ADFIX_PATTERNS = %i[prefix suffix].to_h do |adfix_type|
|
|
463
78
|
patterns = {}
|
|
464
79
|
adfix = ADFIXES[adfix_type]
|
|
465
80
|
|
|
466
|
-
|
|
81
|
+
CONTACT_TYPES.each do |ct|
|
|
467
82
|
with_optional_spaces = adfix[ct].map { |p| p.gsub(ASCII_SPACE, ' *') }
|
|
468
83
|
pattern_string = with_optional_spaces.join('|').gsub('.', '\.*')
|
|
469
|
-
patterns[ct] = /#{adfix[:before]}\(*(?:#{pattern_string})[
|
|
84
|
+
patterns[ct] = /#{adfix[:before]}\(*(?:#{pattern_string})[®™)]*#{adfix[:after]}/i
|
|
470
85
|
end
|
|
471
86
|
|
|
472
87
|
[adfix_type, patterns]
|
|
473
|
-
end
|
|
88
|
+
end
|
|
474
89
|
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NameTamer
|
|
4
|
+
class Name
|
|
5
|
+
module PrivateMethodsNiceName
|
|
6
|
+
def unescape
|
|
7
|
+
@tidy_name = Strings.unescape_html(Strings.safe_unescape(Strings.ensure_safe(@tidy_name)))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def remove_zero_width
|
|
11
|
+
@tidy_name = Strings.strip_unwanted(@tidy_name, ZERO_WIDTH_FILTER)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def tidy_spacing
|
|
15
|
+
@tidy_name = Strings.whitespace_to(Strings.space_around_comma(@tidy_name).strip, ASCII_SPACE)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def fix_encoding_errors
|
|
19
|
+
@tidy_name = Strings.fix_encoding_errors(@tidy_name)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Remove spaces from groups of initials
|
|
23
|
+
def consolidate_initials
|
|
24
|
+
@tidy_name = Strings.ensure_space_after_initials(Strings.remove_spaces_from_initials(@tidy_name))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# An adfix is either a prefix or a suffix
|
|
28
|
+
def remove_adfixes
|
|
29
|
+
if @last_name.nil?
|
|
30
|
+
# Our name is still in one part, not two
|
|
31
|
+
loop do
|
|
32
|
+
@nice_name = remove_outermost_adfix(:suffix, @nice_name)
|
|
33
|
+
break unless @adfix_found
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
loop do
|
|
37
|
+
@nice_name = remove_outermost_adfix(:prefix, @nice_name)
|
|
38
|
+
break unless @adfix_found
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
# Our name is currently in two halves
|
|
42
|
+
loop do
|
|
43
|
+
@last_name = remove_outermost_adfix(:suffix, @last_name)
|
|
44
|
+
break unless @adfix_found
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
loop do
|
|
48
|
+
@remainder = remove_outermost_adfix(:prefix, @remainder)
|
|
49
|
+
break unless @adfix_found
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Names in the form "Smith, John" need to be turned around to "John Smith"
|
|
55
|
+
def fixup_last_name_first
|
|
56
|
+
return if @contact_type == :organization
|
|
57
|
+
|
|
58
|
+
parts = @nice_name.split ', '
|
|
59
|
+
|
|
60
|
+
return unless parts.count == 2
|
|
61
|
+
|
|
62
|
+
@last_name = parts[0] # Sometimes the last name alone is all caps and we can name-case it
|
|
63
|
+
@remainder = parts[1]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Sometimes we end up with mismatched braces after adfix stripping
|
|
67
|
+
# e.g. "Ceres (Ceres Holdings LLC)" -> "Ceres (Ceres Holdings"
|
|
68
|
+
def fixup_mismatched_braces
|
|
69
|
+
left_brace_count = @nice_name.count '('
|
|
70
|
+
right_brace_count = @nice_name.count ')'
|
|
71
|
+
|
|
72
|
+
if left_brace_count > right_brace_count
|
|
73
|
+
@nice_name += ')'
|
|
74
|
+
elsif left_brace_count < right_brace_count
|
|
75
|
+
@nice_name = "(#{@nice_name}"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def name_wrangle
|
|
80
|
+
# Fix case if all caps or all lowercase
|
|
81
|
+
if @last_name.nil?
|
|
82
|
+
name_wrangle_single_name
|
|
83
|
+
else
|
|
84
|
+
name_wrangle_split_name
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def name_wrangle_single_name
|
|
89
|
+
lowercase = @nice_name.downcase
|
|
90
|
+
uppercase = @nice_name.upcase
|
|
91
|
+
fix_case = false
|
|
92
|
+
|
|
93
|
+
if @contact_type == :organization
|
|
94
|
+
fix_case = true if @nice_name == uppercase && @nice_name.length > 4
|
|
95
|
+
elsif [uppercase, lowercase].include?(@nice_name)
|
|
96
|
+
fix_case = true
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
@nice_name = name_case(lowercase) if fix_case
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def name_wrangle_split_name
|
|
103
|
+
# It's a person if we've split the name, so no organization logic here
|
|
104
|
+
lowercase = @last_name.downcase
|
|
105
|
+
uppercase = @last_name.upcase
|
|
106
|
+
@last_name = name_case(lowercase) if [uppercase, lowercase].include?(@last_name)
|
|
107
|
+
@nice_name = "#{@remainder} #{@last_name}"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Conjoin compound names with non-breaking spaces
|
|
111
|
+
def use_nonbreaking_spaces_in_compound_names
|
|
112
|
+
@nice_name = Strings.nbsp_in_name_modifier(Strings.nbsp_in_compound_name(@nice_name))
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module NameTamer
|
|
4
|
+
class Name
|
|
5
|
+
module PrivateMethodsSimpleName
|
|
6
|
+
# Remove initials from personal names unless they are the only identifier.
|
|
7
|
+
# i.e. only remove initials if there's also a proper name there
|
|
8
|
+
def remove_initials
|
|
9
|
+
return unless @contact_type == :person
|
|
10
|
+
|
|
11
|
+
temp_name = @simple_name.gsub(/\b([a-z](?:\.*\s+|\.))/i, '')
|
|
12
|
+
|
|
13
|
+
# If the name still has at least one space we're OK
|
|
14
|
+
@simple_name = temp_name if temp_name.include?(ASCII_SPACE)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def remove_middle_names
|
|
18
|
+
return unless @contact_type == :person
|
|
19
|
+
|
|
20
|
+
first_name, parts = find_first_usable_name(@simple_name.split)
|
|
21
|
+
last_name, = find_last_usable_name(parts)
|
|
22
|
+
|
|
23
|
+
return unless first_name || last_name
|
|
24
|
+
|
|
25
|
+
separator = first_name && last_name ? ' ' : ''
|
|
26
|
+
@simple_name = "#{first_name}#{separator}#{last_name}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def find_first_usable_name(parts)
|
|
30
|
+
part = nil
|
|
31
|
+
|
|
32
|
+
parts.each_index do |i|
|
|
33
|
+
part = parts[i]
|
|
34
|
+
next if part.gsub(FILTER_COMPAT, '').empty?
|
|
35
|
+
|
|
36
|
+
parts = parts.slice(i + 1, parts.length) # don't use "slice!"
|
|
37
|
+
break
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
[part, parts]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def find_last_usable_name(parts)
|
|
44
|
+
part = nil
|
|
45
|
+
|
|
46
|
+
parts.reverse_each do |p|
|
|
47
|
+
next if p.gsub(FILTER_COMPAT, '').empty?
|
|
48
|
+
|
|
49
|
+
part = p
|
|
50
|
+
break
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
part
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def remove_periods_from_initials
|
|
57
|
+
@simple_name = Strings.remove_periods_from_initials(@simple_name)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def standardize_words
|
|
61
|
+
words = @simple_name
|
|
62
|
+
.gsub(/ *& */, ' and ') # replace ampersand characters with ' and '
|
|
63
|
+
.gsub(/ *\+ */, ' plus ') # replace plus signs with ' plus '
|
|
64
|
+
.gsub(/\bintl\b/i, 'International') # replace 'intl' with 'International'
|
|
65
|
+
.gsub(/[־‐‑‒–—―−﹘﹣-]/, SLUG_DELIMITER) # Replace Unicode dashes with ASCII hyphen
|
|
66
|
+
|
|
67
|
+
@simple_name = Strings.strip_unwanted(words, /["“”™℠®©℗]/) # remove quotes and commercial decoration
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|