biodiversity 0.5.14

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.
@@ -0,0 +1,1195 @@
1
+ # encoding: UTF-8
2
+ grammar ScientificNameClean
3
+
4
+ rule root
5
+ space a:scientific_name_5 space {
6
+ def value
7
+ a.value.gsub(/\s{2,}/, ' ').strip
8
+ end
9
+
10
+ def canonical
11
+ a.canonical.gsub(/\s{2,}/, ' ').strip
12
+ end
13
+
14
+ def pos
15
+ a.pos
16
+ end
17
+
18
+ def hybrid
19
+ a.hybrid
20
+ end
21
+
22
+ def details
23
+ a.details.class == Array ? a.details : [a.details]
24
+ end
25
+ }
26
+ end
27
+
28
+ rule scientific_name_5
29
+ a:scientific_name_1 space b:taxon_concept_rank space c:authorship {
30
+ def value
31
+ a.value + " " + b.apply(c)
32
+ end
33
+
34
+ def canonical
35
+ a.canonical
36
+ end
37
+
38
+ def pos
39
+ a.pos.merge(c.pos)
40
+ end
41
+
42
+ def hybrid
43
+ a.hybrid
44
+ end
45
+
46
+ def details
47
+ a.details.merge(b.details(c))
48
+ end
49
+ }
50
+ /
51
+ scientific_name_4
52
+ end
53
+
54
+ rule scientific_name_4
55
+ a:scientific_name_1 space hybrid_character space b:scientific_name_1 {
56
+ def value
57
+ a.value + " × " + b.value
58
+ end
59
+
60
+ def canonical
61
+ a.canonical + " " + b.canonical
62
+ end
63
+
64
+ def pos
65
+ a.pos.merge(b.pos)
66
+ end
67
+
68
+ def hybrid
69
+ true
70
+ end
71
+
72
+ def details
73
+ [a.details, b.details]
74
+ end
75
+ }
76
+ /
77
+ a:scientific_name_1 space hybrid_character space [\?]? {
78
+ def value
79
+ a.value + " × ?"
80
+ end
81
+
82
+ def canonical
83
+ a.canonical
84
+ end
85
+
86
+ def pos
87
+ a.pos
88
+ end
89
+
90
+ def hybrid
91
+ true
92
+ end
93
+
94
+ def details
95
+ [a.details, "?"]
96
+ end
97
+ }
98
+ /
99
+ scientific_name_3
100
+ end
101
+
102
+ rule scientific_name_3
103
+ a:hybrid_character space b:scientific_name_2 {
104
+ def value
105
+ a.value + " " + b.value
106
+ end
107
+
108
+ def canonical
109
+ b.canonical
110
+ end
111
+
112
+ def pos
113
+ b.pos
114
+ end
115
+
116
+ def hybrid
117
+ true
118
+ end
119
+
120
+ def details
121
+ b.details
122
+ end
123
+ }
124
+ /
125
+ scientific_name_2
126
+ end
127
+
128
+ rule scientific_name_2
129
+ a:scientific_name_1 space b:status_part {
130
+ def value
131
+ a.value + " " + b.value
132
+ end
133
+
134
+ def canonical
135
+ a.canonical
136
+ end
137
+
138
+ def pos
139
+ a.pos
140
+ end
141
+
142
+ def hybrid
143
+ a.hybrid rescue false
144
+ end
145
+
146
+ def details
147
+ a.details.merge(b.details)
148
+ end
149
+ }
150
+ /
151
+ scientific_name_1
152
+ end
153
+
154
+ rule scientific_name_1
155
+ multinomial_name
156
+ /
157
+ uninomial_name
158
+ end
159
+
160
+
161
+ rule status_part
162
+ a:status_word space b:status_part {
163
+ def value
164
+ a.value + " " + b.value
165
+ end
166
+ def details
167
+ {:status => value}
168
+ end
169
+ }
170
+ /
171
+ status_word
172
+ end
173
+
174
+ rule status_word
175
+ latin_word [\.] {
176
+ def value
177
+ text_value.strip
178
+ end
179
+ def details
180
+ {:status => value}
181
+ end
182
+ }
183
+ #/
184
+ #latin_word
185
+ end
186
+
187
+
188
+ rule multinomial_name
189
+ a:genus space b:subgenus space species_prefix? space c:species space_hard d:infraspecies_mult {
190
+ def value
191
+ a.value + " " + b.value + " " + c.value + " " + d.value
192
+ end
193
+
194
+ def canonical
195
+ a.canonical + " " + b.canonical + " " + c.canonical + " " + d.canonical
196
+ end
197
+
198
+ def pos
199
+ a.pos.merge(b.pos).merge(c.pos).merge(d.pos)
200
+ end
201
+
202
+ def hybrid
203
+ c.hybrid rescue false
204
+ end
205
+
206
+ def details
207
+ a.details.merge(b.details).merge(c.details).merge(d.details)
208
+ end
209
+ }
210
+ /
211
+ a:genus space b:subgenus space species_prefix? space c:species {
212
+ def value
213
+ a.value + " " + b.value + " " + c.value
214
+ end
215
+
216
+ def canonical
217
+ a.canonical + " " + c.canonical
218
+ end
219
+
220
+ def pos
221
+ a.pos.merge(b.pos).merge(c.pos)
222
+ end
223
+
224
+ def hybrid
225
+ c.hybrid rescue false
226
+ end
227
+
228
+ def details
229
+ a.details.merge(b.details).merge(c.details)
230
+ end
231
+ }
232
+ /
233
+ a:genus space species_prefix? space b:species space_hard c:infraspecies_mult {
234
+ def value
235
+ a.value + " " + b.value + " " + c.value
236
+ end
237
+
238
+ def canonical
239
+ a.canonical + " " + b.canonical + " " + c.canonical
240
+ end
241
+
242
+ def pos
243
+ a.pos.merge(b.pos).merge(c.pos)
244
+ end
245
+
246
+ def hybrid
247
+ b.hybrid rescue false
248
+ end
249
+
250
+ def details
251
+ a.details.merge(b.details).merge(c.details)
252
+ end
253
+ }
254
+ /
255
+ a:genus space species_prefix? space b:species {
256
+ def value
257
+ a.value + " " + b.value
258
+ end
259
+
260
+ def canonical
261
+ a.canonical + " " + b.canonical
262
+ end
263
+
264
+ def pos
265
+ a.pos.merge(b.pos)
266
+ end
267
+
268
+ def hybrid
269
+ b.hybrid rescue false
270
+ end
271
+
272
+ def details
273
+ a.details.merge(b.details)
274
+ end
275
+ }
276
+ end
277
+
278
+ rule infraspecies_mult
279
+ a:infraspecies space b:infraspecies_mult {
280
+ def value
281
+ a.value + " " + b.value
282
+ end
283
+
284
+ def canonical
285
+ a.canonical + " " + b.canonical
286
+ end
287
+
288
+ def pos
289
+ a.pos.merge(b.pos)
290
+ end
291
+
292
+ def details
293
+ a_array = a.details[:infraspecies].class == Array ? a.details[:infraspecies] : [a.details[:infraspecies]]
294
+ b_array = b.details[:infraspecies].class == Array ? b.details[:infraspecies] : [b.details[:infraspecies]]
295
+ a.details.merge({:infraspecies => a_array + b_array})
296
+ end
297
+ }
298
+ /
299
+ infraspecies {
300
+ def details
301
+ {:infraspecies => [super[:infraspecies]]}
302
+ end
303
+ }
304
+ end
305
+
306
+ rule infraspecies
307
+ a:infraspecies_epitheton space b:authorship {
308
+ def value
309
+ a.value + " " + b.value
310
+ end
311
+
312
+ def canonical
313
+ a.canonical
314
+ end
315
+
316
+ def pos
317
+ a.pos.merge(b.pos)
318
+ end
319
+
320
+ def details
321
+ {:infraspecies => a.details[:infraspecies].merge(b.details)}
322
+ end
323
+ }
324
+ /
325
+ infraspecies_epitheton
326
+ end
327
+
328
+ rule infraspecies_epitheton
329
+ sel:rank space_hard a:species_word {
330
+ def value
331
+ sel.apply(a)
332
+ end
333
+ def canonical
334
+ sel.canonical(a)
335
+ end
336
+
337
+ def pos
338
+ {a.interval.begin => ['infraspecies', a.interval.end]}
339
+ end
340
+
341
+ def details
342
+ sel.details(a)
343
+ end
344
+ }
345
+ /
346
+ species_word ![\.] {
347
+ def value
348
+ text_value
349
+ end
350
+
351
+ def canonical
352
+ value
353
+ end
354
+
355
+ def pos
356
+ {interval.begin => ['infraspecies', interval.end]}
357
+ end
358
+
359
+ def details
360
+ {:infraspecies => {:epitheton => value, :rank => 'n/a'}}
361
+ end
362
+ }
363
+ end
364
+
365
+ rule taxon_concept_rank
366
+ ("sec."/"sensu.") {
367
+ def value
368
+ "sec."
369
+ end
370
+ def apply(a)
371
+ " " + value + " " + a.value
372
+ end
373
+ def details(a = nil)
374
+ {:taxon_concept => a.details}
375
+ end
376
+ }
377
+ end
378
+
379
+ rule rank
380
+ ("morph."/"f.sp."/"B"/"ssp."/"mut."/"nat"/"nothosubsp."/"pseudovar."/"sect."/"ser."/"var."/"subvar."/ "[var.]" /"subsp."/"subf."/"race"/"α"
381
+ /"ββ"/"β"/"γ"/"δ"/"ε"/"φ"/"θ"/"μ"/"a."/"b."/"c."/"d."/"e."/"g."/"k."/"****"/"**"/"*")
382
+ {
383
+ def value
384
+ text_value.strip
385
+ end
386
+
387
+ def apply(a)
388
+ " " + text_value + " " + a.value
389
+ end
390
+
391
+ def canonical(a)
392
+ " " + a.value
393
+ end
394
+
395
+ def details(a = nil)
396
+ {:infraspecies => {:epitheton => (a.value rescue nil), :rank => text_value}}
397
+ end
398
+ }
399
+ /
400
+ rank_forma
401
+ end
402
+
403
+ rule rank_forma
404
+ ("forma"/"form."/"fo."/"f.")
405
+ {
406
+ def value
407
+ "f."
408
+ end
409
+ def apply(a)
410
+ " " + value + " " + a.value
411
+ end
412
+ def canonical(a)
413
+ " " + a.value
414
+ end
415
+ def details(a = nil)
416
+ {:infraspecies => {:epitheton => (a.value rescue nil), :rank => value}}
417
+ end
418
+ }
419
+ end
420
+
421
+ rule species
422
+ a:species_epitheton space b:authorship {
423
+ def value
424
+ a.value + " " + b.value
425
+ end
426
+
427
+ def canonical
428
+ a.canonical
429
+ end
430
+
431
+ def hybrid
432
+ a.hybrid rescue false
433
+ end
434
+
435
+ def pos
436
+ a.pos.merge(b.pos)
437
+ end
438
+
439
+ def details
440
+ {:species => a.details[:species].merge(b.details)}
441
+ end
442
+ }
443
+ /
444
+ species_epitheton
445
+ end
446
+
447
+ rule species_epitheton
448
+ a:species_word &(space_hard author_prefix_word space_hard) {
449
+ def value
450
+ a.value
451
+ end
452
+
453
+ def canonical
454
+ a.value
455
+ end
456
+
457
+ def hybrid
458
+ a.hybrid rescue false
459
+ end
460
+
461
+ def pos
462
+ {a.interval.begin => ['species', a.interval.end]}
463
+ end
464
+
465
+ def details
466
+ {:species => {:epitheton => a.value}}
467
+ end
468
+ }
469
+ /
470
+ species_word {
471
+ def canonical
472
+ value
473
+ end
474
+
475
+ def pos
476
+ {interval.begin => ['species', interval.end]}
477
+ end
478
+
479
+ def hybrid
480
+ false
481
+ end
482
+
483
+ def details
484
+ {:species => {:epitheton => value}}
485
+ end
486
+ }
487
+ /
488
+ species_word_hybrid
489
+ end
490
+
491
+ rule subgenus
492
+ left_paren space a:cap_latin_word space right_paren {
493
+ def value
494
+ "(" + a.value + ")"
495
+ end
496
+
497
+ def canonical
498
+ a.value
499
+ end
500
+
501
+ def pos
502
+ {a.interval.begin => ['subgenus', a.interval.end]}
503
+ end
504
+
505
+ def details
506
+ {:subgenus => {:epitheton => a.value}}
507
+ end
508
+ }
509
+ end
510
+
511
+ rule genus
512
+ a:cap_latin_word !(space_hard author_prefix_word space_hard author_word) {
513
+ def value
514
+ a.value
515
+ end
516
+
517
+ def pos
518
+ {a.interval.begin => ['genus', a.interval.end]}
519
+ end
520
+
521
+ def canonical
522
+ a.value
523
+ end
524
+
525
+ def details
526
+ {:genus => {:epitheton => a.value}}
527
+ end
528
+ }
529
+ end
530
+
531
+ rule uninomial_name
532
+ a:uninomial_epitheton space_hard b:authorship {
533
+ def value
534
+ a.value + " " + b.value
535
+ end
536
+
537
+ def canonical
538
+ a.canonical
539
+ end
540
+
541
+ def pos
542
+ a.pos.merge(b.pos)
543
+ end
544
+
545
+ def hybrid
546
+ false
547
+ end
548
+
549
+ def details
550
+ {:uninomial => a.details[:uninomial].merge(b.details)}
551
+ end
552
+ }
553
+ /
554
+ uninomial_epitheton
555
+ end
556
+
557
+ rule uninomial_epitheton
558
+ cap_latin_word {
559
+ def canonical
560
+ value
561
+ end
562
+
563
+ def pos
564
+ {interval.begin => ['uninomial', interval.end]}
565
+ end
566
+
567
+ def hybrid
568
+ false
569
+ end
570
+
571
+ def details
572
+ {:uninomial => {:epitheton => value}}
573
+ end
574
+ }
575
+ end
576
+
577
+ rule authorship
578
+ a:basionym_authorship_with_parenthesis space b:simple_authorship ","? space c:ex_authorship {
579
+ def value
580
+ a.value + " " + b.value + " " + c.value
581
+ end
582
+
583
+ def pos
584
+ a.pos.merge(b.pos).merge(c.pos)
585
+ end
586
+
587
+ def details
588
+ val = {:authorship => text_value.strip, :combinationAuthorTeam => b.details[:basionymAuthorTeam], :basionymAuthorTeam => a.details[:basionymAuthorTeam]}
589
+ val[:combinationAuthorTeam].merge!(c.details)
590
+ val
591
+ end
592
+ }
593
+ /
594
+ a:basionym_authorship_with_parenthesis space b:simple_authorship {
595
+ def value
596
+ a.value + " " + b.value
597
+ end
598
+
599
+ def pos
600
+ a.pos.merge(b.pos)
601
+ end
602
+
603
+ def details
604
+ {:authorship => text_value.strip, :combinationAuthorTeam => b.details[:basionymAuthorTeam], :basionymAuthorTeam => a.details[:basionymAuthorTeam]}
605
+ end
606
+ }
607
+ /
608
+ basionym_authorship_with_parenthesis
609
+ /
610
+ a:simple_authorship ","? space b:ex_authorship {
611
+ def value
612
+ a.value + " " + b.value
613
+ end
614
+
615
+ def pos
616
+ a.pos.merge(b.pos)
617
+ end
618
+
619
+ def details
620
+ val = a.details
621
+ val[:authorship] = text_value.strip
622
+ val[:basionymAuthorTeam].merge!(b.details)
623
+ val
624
+ end
625
+ }
626
+ /
627
+ simple_authorship
628
+ end
629
+
630
+
631
+ rule basionym_authorship_with_parenthesis
632
+ left_paren space a:authors_names space right_paren space [,]? space b:year {
633
+ def value
634
+ "(" + a.value + " " + b.value + ")"
635
+ end
636
+
637
+ def pos
638
+ a.pos.merge(b.pos)
639
+ end
640
+
641
+ def details
642
+ { :authorship => text_value,
643
+ :basionymAuthorTeam => {:author_team => text_value}.merge(a.details).merge(b.details)
644
+ }
645
+ end
646
+ }
647
+ /
648
+ left_paren space a:simple_authorship ","? space b:ex_authorship space right_paren {
649
+ def value
650
+ "(" + a.value + " " + b.value + ")"
651
+ end
652
+
653
+ def pos
654
+ a.pos.merge(b.pos)
655
+ end
656
+
657
+ def details
658
+ val = a.details
659
+ val[:basionymAuthorTeam].merge!(b.details)
660
+ val[:authorship] = text_value.strip
661
+ val
662
+ end
663
+ }
664
+ /
665
+ left_paren space a:simple_authorship space right_paren {
666
+ def value
667
+ "(" + a.value + ")"
668
+ end
669
+
670
+ def pos
671
+ a.pos
672
+ end
673
+
674
+ def details
675
+ val = a.details
676
+ val[:authorship] = text_value
677
+ val
678
+ end
679
+ }
680
+ /
681
+ left_paren space a:"?" space right_paren {
682
+ def value
683
+ "(?)"
684
+ end
685
+
686
+ def pos
687
+ {a.interval.begin => ['unknown_author', a.interval.end]}
688
+ end
689
+
690
+ def details
691
+ {:authorship => text_value, :basionymAuthorTeam => {:authorTeam => text_value, :author => ['?']}}
692
+ end
693
+ }
694
+ end
695
+
696
+ rule ex_authorship
697
+ ex_sep space b:simple_authorship {
698
+ def value
699
+ " ex " + b.value
700
+ end
701
+
702
+ def pos
703
+ b.pos
704
+ end
705
+
706
+ def details
707
+ val = {:exAuthorTeam => {:authorTeam => b.text_value.strip}.merge(b.details[:basionymAuthorTeam])}
708
+ val
709
+ end
710
+ }
711
+ end
712
+
713
+
714
+ rule simple_authorship
715
+ a:authors_names space [,]? space b:year? [,]? space "non" space authors_names space [,]? space year {
716
+ def value
717
+ a.value + " " + b.value
718
+ end
719
+
720
+ def pos
721
+ a.pos.merge(b.pos)
722
+ end
723
+
724
+ def details
725
+ details_with_arg(:basionymAuthorTeam)
726
+ end
727
+
728
+ def details_with_arg(authorTeamType = 'basionymAuthorTeam')
729
+ { :authorship => text_value,
730
+ authorTeamType.to_sym => {
731
+ :authorTeam => a.text_value.strip
732
+ }.merge(a.details).merge(b.details)
733
+ }
734
+ end
735
+ }
736
+ /
737
+ a:authors_names space [,]? space b:year {
738
+ def value
739
+ a.value + " " + b.value
740
+ end
741
+
742
+ def pos
743
+ a.pos.merge(b.pos)
744
+ end
745
+
746
+ def details
747
+ details_with_arg(:basionymAuthorTeam)
748
+ end
749
+
750
+ def details_with_arg(authorTeamType = 'basionymAuthorTeam')
751
+ { :authorship => text_value,
752
+ authorTeamType.to_sym => {
753
+ :authorTeam => a.text_value.strip
754
+ }.merge(a.details).merge(b.details)
755
+ }
756
+ end
757
+ }
758
+ /
759
+ authors_names {
760
+ def details
761
+ details = details_with_arg(:basionymAuthorTeam)
762
+ details[:basionymAuthorTeam].merge!(super)
763
+ details
764
+ end
765
+
766
+ def details_with_arg(authorTeamType = 'basionymAuthorTeam')
767
+ { :authorship => text_value,
768
+ authorTeamType.to_sym => {
769
+ :authorTeam => text_value,
770
+ }
771
+ }
772
+ end
773
+ }
774
+ end
775
+
776
+ rule authors_names
777
+ a:author_name space sep:author_separator space b:authors_names {
778
+ def value
779
+ sep.apply(a,b)
780
+ end
781
+
782
+ def pos
783
+ sep.pos(a,b)
784
+ end
785
+
786
+ def details
787
+ sep.details(a,b)
788
+ end
789
+ }
790
+ /
791
+ author_name
792
+ /
793
+ unknown_auth
794
+ end
795
+
796
+
797
+ rule unknown_auth
798
+ ("auct."/"hort."/"anon."/"ht.") {
799
+ def value
800
+ text_value
801
+ end
802
+
803
+ def pos
804
+ {interval.begin => ['unknown_author', interval.end]}
805
+ end
806
+
807
+ def details
808
+ {:author => ["unknown"]}
809
+ end
810
+ }
811
+ end
812
+
813
+ rule ex_sep
814
+ ("ex"/"in") &[\s]
815
+ end
816
+
817
+ rule author_separator
818
+ ("&"/","/"and"/"et") {
819
+ def apply(a,b)
820
+ sep = text_value.strip
821
+ sep = " et" if ["&","and","et"].include? sep
822
+ a.value + sep + " " + b.value
823
+ end
824
+
825
+ def pos(a,b)
826
+ a.pos.merge(b.pos)
827
+ end
828
+
829
+ def details(a,b)
830
+ {:author => a.details[:author] + b.details[:author]}
831
+ end
832
+ }
833
+ end
834
+
835
+ rule author_name
836
+ space a:author_prefix_word space b:author_name space {
837
+ def value
838
+ a.value + " " + b.value
839
+ end
840
+
841
+ def pos
842
+ a.pos.merge(b.pos)
843
+ end
844
+
845
+ def details
846
+ {:author => [value]}
847
+ end
848
+ }
849
+ /
850
+ space a:author_word space b:author_name space {
851
+ def value
852
+ a.value + " " + b.value
853
+ end
854
+
855
+ def pos
856
+ a.pos.merge(b.pos)
857
+ end
858
+
859
+ def details
860
+ {:author => [value]}
861
+ end
862
+ }
863
+ /
864
+ author_word
865
+ end
866
+
867
+ rule author_word
868
+ "A S. Xu" {
869
+ def value
870
+ text_value.strip
871
+ end
872
+
873
+ def pos
874
+ {interval.begin => ['author_word', 1], (interval.begin + 2) => ['author_word', 2], (interval.begin + 5) => ['author_word', 2]}
875
+ end
876
+
877
+ def details
878
+ {:author => [value]}
879
+ end
880
+ }
881
+ /
882
+ ("arg."/"et al.\{\?\}"/"et al.") {
883
+ def value
884
+ text_value.strip
885
+ end
886
+
887
+ def pos
888
+ #cheating because there are several words in some of them
889
+ {interval.begin => ['author_word', interval.end]}
890
+ end
891
+
892
+ def details
893
+ {:author => [value]}
894
+ end
895
+ }
896
+ /
897
+ ("Å"/"Ö"/"Á"/"Ø"/"Ô"/"Š"/"Ś"/"Č"/"Ķ"/"Ł"/"É"/"Ž"/[A-W]/[Y-Z]) [^0-9\[\]\(\)\s&,]* {
898
+ def value
899
+ text_value
900
+ end
901
+
902
+ def pos
903
+ {interval.begin => ['author_word', interval.end]}
904
+ end
905
+
906
+ def details
907
+ {:author => [value]}
908
+ end
909
+ }
910
+ /
911
+ "X" [^0-9\[\]\(\)\s&,]+ {
912
+ def value
913
+ text_value
914
+ end
915
+
916
+ def pos
917
+ {interval.begin => ['author_word', interval.end]}
918
+ end
919
+
920
+ def details
921
+ {:author => [value]}
922
+ end
923
+ }
924
+ /
925
+ author_prefix_word
926
+ end
927
+
928
+ rule author_prefix_word
929
+ space ("ab"/"bis"/"da"/"der"/"den"/"della"/"dela"/"de"/"di"/"du"/"la"/"ter"/"van"/"von") &space_hard {
930
+ def value
931
+ text_value
932
+ end
933
+
934
+ def pos
935
+ #cheating because there are several words in some of them
936
+ {interval.begin => ['author_word', interval.end]}
937
+ end
938
+ }
939
+ end
940
+
941
+ rule cap_latin_word
942
+ a:([A-Z]/cap_digraph) b:latin_word "?" {
943
+ def value
944
+ (a.value rescue a.text_value) + b.value
945
+ end
946
+ }
947
+ /
948
+ a:([A-Z]/cap_digraph) b:latin_word {
949
+ def value
950
+ (a.value rescue a.text_value) + b.value
951
+ end
952
+ }
953
+ /
954
+ ("Ca"/"Ea"/"Ge"/"Ia"/"Io"/"Io"/"Ix"/"Lo"/"Oa"/"Ra"/"Ty"/"Ua"/"Aa"/"Ja"/"Zu"/"La"/"Qu"/"As"/"Ba") {
955
+ def value
956
+ text_value
957
+ end
958
+ }
959
+ end
960
+
961
+ rule species_word_hybrid
962
+ a:multiplication_sign space b:species_word {
963
+ def value
964
+ a.value + " " + b.value
965
+ end
966
+
967
+ def canonical
968
+ b.value
969
+ end
970
+
971
+ def hybrid
972
+ true
973
+ end
974
+
975
+ def pos
976
+ {b.interval.begin => ['species', b.interval.end]}
977
+ end
978
+
979
+ def details
980
+ {:species => {:epitheton => b.value}}
981
+ end
982
+ }
983
+ /
984
+ a:"X" space b:species_word {
985
+ def value
986
+ "× " + b.value
987
+ end
988
+
989
+ def canonical
990
+ b.value
991
+ end
992
+
993
+ def hybrid
994
+ true
995
+ end
996
+
997
+ def pos
998
+ {b.interval.begin => ['species', b.interval.end]}
999
+ end
1000
+
1001
+ def details
1002
+ {:species => {:epitheton => b.value}}
1003
+ end
1004
+ }
1005
+ /
1006
+ a:"x" space_hard b:species_word {
1007
+ def value
1008
+ "× " + b.value
1009
+ end
1010
+
1011
+ def canonical
1012
+ b.value
1013
+ end
1014
+
1015
+ def hybrid
1016
+ true
1017
+ end
1018
+
1019
+ def pos
1020
+ {b.interval.begin => ['species', b.interval.end]}
1021
+ end
1022
+
1023
+ def details
1024
+ {:species => {:epitheton => b.value}}
1025
+ end
1026
+ }
1027
+ end
1028
+
1029
+ rule species_prefix
1030
+ ("aff."/"corrig."/"?") &space_hard
1031
+ end
1032
+
1033
+ rule species_word
1034
+ a:[0-9]+ "-"? b:latin_word {
1035
+ def value
1036
+ a.text_value + "-" + b.value
1037
+ end
1038
+ }
1039
+ /
1040
+ latin_word
1041
+ end
1042
+
1043
+ rule latin_word
1044
+ a:[a-zëüäöïéåóç] b:full_name_letters {
1045
+ def value
1046
+ a.text_value + b.value
1047
+ end
1048
+ }
1049
+ /
1050
+ a:digraph b:full_name_letters {
1051
+ def value
1052
+ a.value + b.value
1053
+ end
1054
+ }
1055
+ end
1056
+
1057
+ rule full_name_letters
1058
+ a:digraph b:full_name_letters {
1059
+ def value
1060
+ a.value + b.value
1061
+ end
1062
+ }
1063
+ /
1064
+ a:valid_name_letters b:digraph c:full_name_letters {
1065
+ def value
1066
+ a.value + b.value + c.value
1067
+ end
1068
+ }
1069
+ /
1070
+ valid_name_letters
1071
+ end
1072
+
1073
+ rule valid_name_letters
1074
+ [a-z\-ëüäöïéåóç]+ {
1075
+ def value
1076
+ text_value
1077
+ end
1078
+ }
1079
+ end
1080
+
1081
+ rule cap_digraph
1082
+ "Æ" {
1083
+ def value
1084
+ 'Ae'
1085
+ end
1086
+ }
1087
+ /
1088
+ "Œ" {
1089
+ def value
1090
+ 'Oe'
1091
+ end
1092
+ }
1093
+ end
1094
+
1095
+ rule digraph
1096
+ "æ" {
1097
+ def value
1098
+ 'ae'
1099
+ end
1100
+ }
1101
+ /
1102
+ "œ" {
1103
+ def value
1104
+ 'oe'
1105
+ end
1106
+ }
1107
+ end
1108
+
1109
+ rule year
1110
+ b:left_paren space a:(year_number_with_character/year_number) space c:right_paren {
1111
+ def value
1112
+ a.value
1113
+ end
1114
+
1115
+ def pos
1116
+ a.pos
1117
+ end
1118
+
1119
+ def details
1120
+ a.details
1121
+ end
1122
+ }
1123
+ /
1124
+ year_number_with_character
1125
+ /
1126
+ year_number
1127
+ end
1128
+
1129
+ rule year_number_with_character
1130
+ a:year_number [a-zA-Z] {
1131
+ def value
1132
+ a.text_value
1133
+ end
1134
+
1135
+ def pos
1136
+ {interval.begin => ['year', interval.end]}
1137
+ end
1138
+
1139
+ def details
1140
+ {:year => value}
1141
+ end
1142
+ }
1143
+ end
1144
+
1145
+ rule year_number
1146
+ [12] [7890] [0-9] [0-9]? [\?]? {
1147
+ def value
1148
+ text_value
1149
+ end
1150
+
1151
+ def pos
1152
+ {interval.begin => ['year', interval.end]}
1153
+ end
1154
+
1155
+ def details
1156
+ {:year => value}
1157
+ end
1158
+ }
1159
+ end
1160
+
1161
+ rule left_paren
1162
+ "("
1163
+ end
1164
+
1165
+ rule right_paren
1166
+ ")"
1167
+ end
1168
+
1169
+ rule hybrid_character
1170
+ ("x"/"X") {
1171
+ def value
1172
+ "×"
1173
+ end
1174
+ }
1175
+ /
1176
+ multiplication_sign
1177
+ end
1178
+
1179
+ rule multiplication_sign
1180
+ "×" {
1181
+ def value
1182
+ text_value
1183
+ end
1184
+ }
1185
+ end
1186
+
1187
+ rule space
1188
+ [\s]*
1189
+ end
1190
+
1191
+ rule space_hard
1192
+ [\s]+
1193
+ end
1194
+
1195
+ end