fbtxt-parser 0.9.0
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 +7 -0
- data/CHANGELOG.md +4 -0
- data/Manifest.txt +50 -0
- data/README.md +22 -0
- data/Rakefile +53 -0
- data/lib/fbtxt/parser/debuggable.rb +53 -0
- data/lib/fbtxt/parser/lexer-logger.rb +20 -0
- data/lib/fbtxt/parser/lexer-on_goal.rb +167 -0
- data/lib/fbtxt/parser/lexer-on_group_def.rb +31 -0
- data/lib/fbtxt/parser/lexer-on_prop_lineup.rb +79 -0
- data/lib/fbtxt/parser/lexer-on_prop_misc.rb +123 -0
- data/lib/fbtxt/parser/lexer-on_prop_penalties.rb +40 -0
- data/lib/fbtxt/parser/lexer-on_round_def.rb +37 -0
- data/lib/fbtxt/parser/lexer-on_top.rb +133 -0
- data/lib/fbtxt/parser/lexer-prep_doc.rb +131 -0
- data/lib/fbtxt/parser/lexer-prep_line.rb +63 -0
- data/lib/fbtxt/parser/lexer-tokenize.rb +468 -0
- data/lib/fbtxt/parser/lexer.rb +231 -0
- data/lib/fbtxt/parser/lexer_buffer.rb +68 -0
- data/lib/fbtxt/parser/lexer_token.rb +126 -0
- data/lib/fbtxt/parser/parse_tree--core.rb +29 -0
- data/lib/fbtxt/parser/parse_tree-match.rb +309 -0
- data/lib/fbtxt/parser/parse_tree-props.rb +233 -0
- data/lib/fbtxt/parser/parse_tree.rb +202 -0
- data/lib/fbtxt/parser/parser-runtime.rb +379 -0
- data/lib/fbtxt/parser/parser-top.rb +102 -0
- data/lib/fbtxt/parser/parser.rb +2343 -0
- data/lib/fbtxt/parser/token-date--helpers.rb +130 -0
- data/lib/fbtxt/parser/token-date--names.rb +108 -0
- data/lib/fbtxt/parser/token-date.rb +200 -0
- data/lib/fbtxt/parser/token-date_duration.rb +171 -0
- data/lib/fbtxt/parser/token-geo.rb +134 -0
- data/lib/fbtxt/parser/token-goals--helpers.rb +114 -0
- data/lib/fbtxt/parser/token-goals.rb +306 -0
- data/lib/fbtxt/parser/token-group.rb +29 -0
- data/lib/fbtxt/parser/token-note.rb +40 -0
- data/lib/fbtxt/parser/token-prop.rb +309 -0
- data/lib/fbtxt/parser/token-prop_name.rb +83 -0
- data/lib/fbtxt/parser/token-round.rb +88 -0
- data/lib/fbtxt/parser/token-score--helpers.rb +189 -0
- data/lib/fbtxt/parser/token-score.rb +60 -0
- data/lib/fbtxt/parser/token-score_full.rb +331 -0
- data/lib/fbtxt/parser/token-score_fuller.rb +434 -0
- data/lib/fbtxt/parser/token-score_legs.rb +59 -0
- data/lib/fbtxt/parser/token-status.rb +192 -0
- data/lib/fbtxt/parser/token-status_inline.rb +112 -0
- data/lib/fbtxt/parser/token-text.rb +221 -0
- data/lib/fbtxt/parser/token-time.rb +144 -0
- data/lib/fbtxt/parser/token.rb +224 -0
- data/lib/fbtxt/parser/version.rb +24 -0
- data/lib/fbtxt/parser.rb +140 -0
- metadata +145 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
module Fbtxt
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## "internal" date helpers
|
|
6
|
+
def self._build_date( m )
|
|
7
|
+
date = {}
|
|
8
|
+
## map month names
|
|
9
|
+
## note - allow any/upcase JULY/JUL etc. thus ALWAYS downcase for lookup
|
|
10
|
+
date[:y] = m[:year].to_i(10) if m[:year]
|
|
11
|
+
## check - use y too for two-digit year or keep separate - why? why not?
|
|
12
|
+
date[:yy] = m[:yy].to_i(10) if m[:yy] ## two digit year (e.g. 25 or 78 etc.)
|
|
13
|
+
date[:m] = m[:month].to_i(10) if m[:month]
|
|
14
|
+
date[:m] = MONTH_MAP[ m[:month_name].downcase ] if m[:month_name]
|
|
15
|
+
date[:d] = m[:day].to_i(10) if m[:day]
|
|
16
|
+
date[:wday] = DAY_MAP[ m[:day_name].downcase ] if m[:day_name]
|
|
17
|
+
|
|
18
|
+
date
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self._build_date_legs( m )
|
|
22
|
+
legs = {}
|
|
23
|
+
## map month names
|
|
24
|
+
## note - allow any/upcase JULY/JUL etc. thus ALWAYS downcase for lookup
|
|
25
|
+
date = {}
|
|
26
|
+
date[:m] = MONTH_MAP[ m[:month_name1].downcase ]
|
|
27
|
+
date[:d] = m[:day1].to_i(10)
|
|
28
|
+
legs[:date1] = date
|
|
29
|
+
|
|
30
|
+
date = {}
|
|
31
|
+
date[:m] = MONTH_MAP[ m[:month_name2].downcase ] if m[:month_name2]
|
|
32
|
+
date[:d] = m[:day2].to_i(10)
|
|
33
|
+
legs[:date2] = date
|
|
34
|
+
|
|
35
|
+
legs
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def self._build_duration( m )
|
|
40
|
+
## todo/check/fix - if end: works for kwargs!!!!!
|
|
41
|
+
duration = { start: {}, end: {}}
|
|
42
|
+
|
|
43
|
+
duration[:start][:y] = m[:year1].to_i(10) if m[:year1]
|
|
44
|
+
duration[:start][:m] = MONTH_MAP[ m[:month_name1].downcase ] if m[:month_name1]
|
|
45
|
+
duration[:start][:d] = m[:day1].to_i(10) if m[:day1]
|
|
46
|
+
duration[:start][:wday] = DAY_MAP[ m[:day_name1].downcase ] if m[:day_name1]
|
|
47
|
+
|
|
48
|
+
duration[:end][:y] = m[:year2].to_i(10) if m[:year2]
|
|
49
|
+
duration[:end][:m] = MONTH_MAP[ m[:month_name2].downcase ] if m[:month_name2]
|
|
50
|
+
duration[:end][:d] = m[:day2].to_i(10) if m[:day2]
|
|
51
|
+
duration[:end][:wday] = DAY_MAP[ m[:day_name2].downcase ] if m[:day_name2]
|
|
52
|
+
|
|
53
|
+
duration
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _build_date( m ) self.class._build_date( m ); end
|
|
60
|
+
def _build_date_legs( m ) self.class._build_date_legs( m ); end
|
|
61
|
+
def _build_duration( m ) self.class._build_duration( m ); end
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
#############
|
|
67
|
+
## "top-level" add a date parser helper
|
|
68
|
+
|
|
69
|
+
## note: parse_date - returns Date object
|
|
70
|
+
## _parse_date (with underscore) - return hash of "parsed" regex match data!!
|
|
71
|
+
|
|
72
|
+
def self.parse_date( str, start: nil )
|
|
73
|
+
if m = _parse_date( str )
|
|
74
|
+
year = m[:y]
|
|
75
|
+
yy = m[:yy]
|
|
76
|
+
|
|
77
|
+
####
|
|
78
|
+
## support two digit shortcut for year
|
|
79
|
+
if yy && year.nil?
|
|
80
|
+
###
|
|
81
|
+
## for now assume 00,01 to 30 is 2000,2001 to 2030
|
|
82
|
+
## and 31 to 99 is 1931 to 1999
|
|
83
|
+
year = yy <= 30 ? 2000+yy : 1900+yy
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
month = m[:m]
|
|
87
|
+
day = m[:d]
|
|
88
|
+
wday = m[:wday]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if year.nil? ## try to calculate year
|
|
92
|
+
raise ArgumentError, "year required in date >#{str}< or pass along start date" if start.nil?
|
|
93
|
+
|
|
94
|
+
year = if month > start.month ||
|
|
95
|
+
(month == start.month && day >= start.day)
|
|
96
|
+
# assume same year as start_at event (e.g. 2013 for 2013/14 season)
|
|
97
|
+
start.year
|
|
98
|
+
else
|
|
99
|
+
# assume year+1 as start_at event (e.g. 2014 for 2013/14 season)
|
|
100
|
+
start.year+1
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
Date.new( year,month,day )
|
|
104
|
+
else
|
|
105
|
+
raise ArgumentError, "unexpected date format; cannot parse >#{str}<"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def self._parse_date( str )
|
|
112
|
+
## note - strip - leading/trailing spaces automatic - why? why not?
|
|
113
|
+
m = DATE_RE.match( str.strip )
|
|
114
|
+
|
|
115
|
+
if m && m.pre_match == '' && m.post_match == ''
|
|
116
|
+
## return hash table with captured components
|
|
117
|
+
date = _build_date( m )
|
|
118
|
+
date
|
|
119
|
+
elsif m
|
|
120
|
+
## note - match BUT not anchored to start and end-of-string!!!
|
|
121
|
+
## report, error somehow??
|
|
122
|
+
nil
|
|
123
|
+
else
|
|
124
|
+
nil ## no match - return nil
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
end # class Lexer
|
|
130
|
+
end # module Fbtxt
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
module Fbtxt
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def self.parse_names( txt )
|
|
6
|
+
lines = [] # array of lines (with words)
|
|
7
|
+
|
|
8
|
+
txt.each_line do |line|
|
|
9
|
+
line = line.strip
|
|
10
|
+
|
|
11
|
+
next if line.empty?
|
|
12
|
+
next if line.start_with?( '#' ) ## skip comments too
|
|
13
|
+
|
|
14
|
+
## strip inline (until end-of-line) comments too
|
|
15
|
+
## e.g. Janvier Janv Jan ## check janv in use??
|
|
16
|
+
## => Janvier Janv Jan
|
|
17
|
+
|
|
18
|
+
line = line.sub( /#.*/, '' ).strip
|
|
19
|
+
## pp line
|
|
20
|
+
|
|
21
|
+
values = line.split( /[ \t]+/ )
|
|
22
|
+
## pp values
|
|
23
|
+
|
|
24
|
+
## todo/fix -- add check for duplicates
|
|
25
|
+
lines << values
|
|
26
|
+
end
|
|
27
|
+
lines
|
|
28
|
+
|
|
29
|
+
end # method parse
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def self.build_names( lines )
|
|
33
|
+
## join all words together into a single string e.g.
|
|
34
|
+
## January|Jan|February|Feb|March|Mar|April|Apr|May|June|Jun|...
|
|
35
|
+
lines.map { |line| line.join('|') }.join('|')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def self.build_map( lines, downcase: false )
|
|
40
|
+
## note: downcase name!!!
|
|
41
|
+
## build a lookup map that maps the word to the index (line no) plus 1 e.g.
|
|
42
|
+
## {"january" => 1, "jan" => 1,
|
|
43
|
+
## "february" => 2, "feb" => 2,
|
|
44
|
+
## "march" => 3, "mar" => 3,
|
|
45
|
+
## "april" => 4, "apr" => 4,
|
|
46
|
+
## "may" => 5,
|
|
47
|
+
## "june" => 6, "jun" => 6, ...
|
|
48
|
+
lines.each_with_index.reduce( {} ) do |h,(line,i)|
|
|
49
|
+
line.each do |name|
|
|
50
|
+
h[ downcase ? name.downcase : name ] = i+1
|
|
51
|
+
end ## note: start mapping with 1 (and NOT zero-based, that is, 0)
|
|
52
|
+
h
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
MONTH_LINES = parse_names( <<TXT )
|
|
60
|
+
January Jan
|
|
61
|
+
February Feb
|
|
62
|
+
March Mar
|
|
63
|
+
April Apr
|
|
64
|
+
May
|
|
65
|
+
June Jun
|
|
66
|
+
July Jul
|
|
67
|
+
August Aug
|
|
68
|
+
September Sept Sep
|
|
69
|
+
October Oct
|
|
70
|
+
November Nov
|
|
71
|
+
December Dec
|
|
72
|
+
TXT
|
|
73
|
+
|
|
74
|
+
MONTH_NAMES = build_names( MONTH_LINES )
|
|
75
|
+
# pp MONTH_NAMES
|
|
76
|
+
MONTH_MAP = build_map( MONTH_LINES, downcase: true )
|
|
77
|
+
# pp MONTH_MAP
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
DAY_LINES = parse_names( <<TXT )
|
|
82
|
+
Monday Mon Mo
|
|
83
|
+
Tuesday Tues Tue Tu
|
|
84
|
+
Wednesday Wed We
|
|
85
|
+
Thursday Thurs Thur Thu Th
|
|
86
|
+
Friday Fri Fr
|
|
87
|
+
Saturday Sat Sa
|
|
88
|
+
Sunday Sun Su
|
|
89
|
+
TXT
|
|
90
|
+
|
|
91
|
+
DAY_NAMES = build_names( DAY_LINES )
|
|
92
|
+
# pp DAY_NAMES
|
|
93
|
+
DAY_MAP = build_map( DAY_LINES, downcase: true )
|
|
94
|
+
# pp DAY_MAP
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
#=>
|
|
98
|
+
# "January|Jan|February|Feb|March|Mar|April|Apr|May|June|Jun|
|
|
99
|
+
# July|Jul|August|Aug|September|Sept|Sep|October|Oct|
|
|
100
|
+
# November|Nov|December|Dec"
|
|
101
|
+
#
|
|
102
|
+
# "Monday|Mon|Mo|Tuesday|Tues|Tue|Tu|Wednesday|Wed|We|
|
|
103
|
+
# Thursday|Thurs|Thur|Thu|Th|Friday|Fri|Fr|
|
|
104
|
+
# Saturday|Sat|Sa|Sunday|Sun|Su"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
end # class Lexer
|
|
108
|
+
end # module Fbtxt
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
module Fbtxt
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# e.g. Fri Aug 9
|
|
7
|
+
# Fri Aug 9
|
|
8
|
+
## Fri, Aug 9
|
|
9
|
+
## Fri, Aug 9 2024
|
|
10
|
+
## Fri, Aug 9, 2024
|
|
11
|
+
## Aug 9, 2024
|
|
12
|
+
## Aug 9, 2024
|
|
13
|
+
## note - eat-up optional comma after DAY_NAMES!!
|
|
14
|
+
##
|
|
15
|
+
## note - Fri Aug/9 no longer supported!!!
|
|
16
|
+
DATE_I_RE = %r{
|
|
17
|
+
(?<date>
|
|
18
|
+
\b
|
|
19
|
+
## optional day name
|
|
20
|
+
((?<day_name>#{DAY_NAMES})
|
|
21
|
+
(?: ,?[ ]+)
|
|
22
|
+
)?
|
|
23
|
+
(?<month_name>#{MONTH_NAMES})
|
|
24
|
+
[ ]
|
|
25
|
+
(?<day>\d{1,2})
|
|
26
|
+
\b
|
|
27
|
+
## optional year
|
|
28
|
+
( ,? [ ] ## note - comma optinal with single space required for now
|
|
29
|
+
(?<year>\d{4}) ## optional year 2025 (yyyy)
|
|
30
|
+
\b
|
|
31
|
+
)?
|
|
32
|
+
)}ix
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### todo/fix - add (opt) day_name later
|
|
36
|
+
## add (opt) year later
|
|
37
|
+
# e.g. Aug 9 & Aug 10
|
|
38
|
+
### note - allow shortcut e.g. Aug 9 & 10
|
|
39
|
+
DATE_LEGS_I_RE = %r{
|
|
40
|
+
(?<date_legs>
|
|
41
|
+
\b
|
|
42
|
+
(?<month_name1>#{MONTH_NAMES})
|
|
43
|
+
[ ]
|
|
44
|
+
(?<day1>\d{1,2})
|
|
45
|
+
[ ] & [ ]
|
|
46
|
+
(?:
|
|
47
|
+
(?<month_name2>#{MONTH_NAMES})
|
|
48
|
+
[ ]
|
|
49
|
+
)? ## note - make 2nd month_name optional
|
|
50
|
+
(?<day2>\d{1,2})
|
|
51
|
+
\b
|
|
52
|
+
)}ix
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
###
|
|
56
|
+
# e.g. 3 June or 10 June
|
|
57
|
+
## note - allow more spaces between DAY_NAMES and DAY e.g.
|
|
58
|
+
## Sun 1 Mar
|
|
59
|
+
## Wed 4 Mar
|
|
60
|
+
## Sat 14 Mar
|
|
61
|
+
## Sat 11 Apr
|
|
62
|
+
## Sat 11 Apr 2021
|
|
63
|
+
## Sat 11 Apr 21
|
|
64
|
+
##
|
|
65
|
+
## Sat, 11 Apr
|
|
66
|
+
## note - eat-up optional comma after DAY_NAMES!!
|
|
67
|
+
##
|
|
68
|
+
## note - Sat 14 Mar 17:30
|
|
69
|
+
## check two-digit year (with NEGATIVE lookahead for time!!!)
|
|
70
|
+
|
|
71
|
+
DATE_II_RE = %r{
|
|
72
|
+
(?<date>
|
|
73
|
+
\b
|
|
74
|
+
## optional day name
|
|
75
|
+
((?<day_name>#{DAY_NAMES})
|
|
76
|
+
(?: ,?[ ]+)
|
|
77
|
+
)?
|
|
78
|
+
(?<day>\d{1,2})
|
|
79
|
+
[ ]
|
|
80
|
+
(?<month_name>#{MONTH_NAMES})
|
|
81
|
+
\b
|
|
82
|
+
## optional year
|
|
83
|
+
( [ ]
|
|
84
|
+
(?:
|
|
85
|
+
(?<year>\d{4}) ## optional year 2025 (yyyy)
|
|
86
|
+
|
|
|
87
|
+
(?:
|
|
88
|
+
(?<yy>\d{2}) ## optional year 25 (yy)
|
|
89
|
+
## check NEGATIVE lookahead
|
|
90
|
+
(?! :|[:h]\d{2})
|
|
91
|
+
)
|
|
92
|
+
)
|
|
93
|
+
\b
|
|
94
|
+
)?
|
|
95
|
+
)}ix
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# e.g. iso-date - 2011-08-25
|
|
99
|
+
## note - allow/support ("shortcuts") e.g 2011-8-25 or 2011-8-3 / 2011-08-03 etc.
|
|
100
|
+
DATE_III_A_RE = %r{
|
|
101
|
+
(?<date>
|
|
102
|
+
\b
|
|
103
|
+
(?<year>\d{4})
|
|
104
|
+
-
|
|
105
|
+
(?<month>\d{1,2})
|
|
106
|
+
-
|
|
107
|
+
(?<day>\d{1,2})
|
|
108
|
+
\b
|
|
109
|
+
)}ix
|
|
110
|
+
|
|
111
|
+
## starting w/ day/month/year e.g. 25-08-2011
|
|
112
|
+
DATE_III_B_RE = %r{
|
|
113
|
+
(?<date>
|
|
114
|
+
\b
|
|
115
|
+
## optional day name
|
|
116
|
+
((?<day_name>#{DAY_NAMES})
|
|
117
|
+
(?: ,?[ ]+)
|
|
118
|
+
)?
|
|
119
|
+
(?<day>\d{1,2})
|
|
120
|
+
-
|
|
121
|
+
(?<month>\d{1,2})
|
|
122
|
+
-
|
|
123
|
+
(?<year>\d{4})
|
|
124
|
+
\b
|
|
125
|
+
)}ix
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
## allow (short)"european" style 8.8.
|
|
130
|
+
## note - assume day/month!!!
|
|
131
|
+
DATE_IIII_RE = %r{
|
|
132
|
+
(?<date>
|
|
133
|
+
\b
|
|
134
|
+
## optional day name
|
|
135
|
+
((?<day_name>#{DAY_NAMES})
|
|
136
|
+
(?: ,?[ ]+)
|
|
137
|
+
)?
|
|
138
|
+
(?<day>\d{1,2})
|
|
139
|
+
\.
|
|
140
|
+
(?<month>\d{1,2})
|
|
141
|
+
\.
|
|
142
|
+
(?: (?:
|
|
143
|
+
(?<year>\d{4}) ## optional year 2025 (yyyy)
|
|
144
|
+
|
|
|
145
|
+
(?<yy>\d{2}) ## optional year 25 (yy)
|
|
146
|
+
)
|
|
147
|
+
\b
|
|
148
|
+
)?
|
|
149
|
+
)
|
|
150
|
+
}ix
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
####################
|
|
154
|
+
### 04/03/2026 or 4/3/2026
|
|
155
|
+
## 04/03/26 or 4/3/26
|
|
156
|
+
## 04/03 or 4/3
|
|
157
|
+
DATE_IIIII_RE = %r{
|
|
158
|
+
(?<date>
|
|
159
|
+
\b
|
|
160
|
+
## optional day name
|
|
161
|
+
((?<day_name>#{DAY_NAMES})
|
|
162
|
+
(?: ,?[ ]+)
|
|
163
|
+
)?
|
|
164
|
+
(?<day>\d{1,2})
|
|
165
|
+
/
|
|
166
|
+
(?<month>\d{1,2})
|
|
167
|
+
\b
|
|
168
|
+
(?:
|
|
169
|
+
/
|
|
170
|
+
(?:
|
|
171
|
+
(?<year>\d{4}) ## optional year 2025 (yyyy)
|
|
172
|
+
|
|
|
173
|
+
(?<yy>\d{2}) ## optional year 25 (yy)
|
|
174
|
+
)
|
|
175
|
+
\b
|
|
176
|
+
)?
|
|
177
|
+
)
|
|
178
|
+
}ix
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
#############################################
|
|
183
|
+
# map tables
|
|
184
|
+
# note: order matters; first come-first matched/served
|
|
185
|
+
DATE_RE = Regexp.union(
|
|
186
|
+
DATE_I_RE,
|
|
187
|
+
DATE_II_RE,
|
|
188
|
+
DATE_III_A_RE, ## e.g. 1973-08-14
|
|
189
|
+
DATE_III_B_RE,
|
|
190
|
+
DATE_IIII_RE, ## e.g. 8.8. or 8.13.79 or 08.14.1973
|
|
191
|
+
DATE_IIIII_RE, ## e.g. 08/14/1973
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
## todo - add more format style here; change to Regexp.union later!!!
|
|
195
|
+
DATE_LEGS_RE = DATE_LEGS_I_RE
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
end # class Lexer
|
|
200
|
+
end # module Fbtxt
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
module Fbtxt
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
###
|
|
8
|
+
# date duration
|
|
9
|
+
# use - or + as separator
|
|
10
|
+
# in theory plus( +) only if dates
|
|
11
|
+
# are two days next to each other
|
|
12
|
+
#
|
|
13
|
+
# otherwise define new dates type in the future? why? why not?
|
|
14
|
+
#
|
|
15
|
+
# check for plus (+) if dates are next to each other (t+1) - why? why not?
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# Sun Jun 23 - Wed Jun 26 -- YES
|
|
19
|
+
# Jun 23 - Jun 26 -- YES
|
|
20
|
+
# Jun 25 - 26 - why? why not??? - YES - see blow variant iii!!!
|
|
21
|
+
|
|
22
|
+
# Tue Jun 25 + Wed Jun 26 -- NO
|
|
23
|
+
# Jun 25 + Jun 26 -- NO
|
|
24
|
+
# Jun 25 .. 26 - why? why not???
|
|
25
|
+
# Jun 25 to 26 - why? why not???
|
|
26
|
+
# Jun 25 + 26 - add - why? why not???
|
|
27
|
+
# Sun-Wed Jun 23-26 - add - why? why not???
|
|
28
|
+
# Wed+Thu Jun 26+27 2024 - add - why? why not???
|
|
29
|
+
#
|
|
30
|
+
# maybe use comma and plus for list of dates
|
|
31
|
+
# Tue Jun 25, Wed Jun 26, Thu Jun 27 ??
|
|
32
|
+
# Tue Jun 25 + Wed Jun 26 + Thu Jun 27 ??
|
|
33
|
+
#
|
|
34
|
+
# add back optional comma (before) year - why? why not?
|
|
35
|
+
#
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
##
|
|
39
|
+
# todo add plus later on - why? why not?
|
|
40
|
+
### todo/fix add optional comma (,) before year
|
|
41
|
+
|
|
42
|
+
### regex note/tip/remindr - \b () \b MUST always get enclosed in parantheses
|
|
43
|
+
## because alternation (|) has lowest priority/binding
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
DURATION_I_RE = %r{
|
|
47
|
+
(?<duration>
|
|
48
|
+
\b
|
|
49
|
+
(?:
|
|
50
|
+
## optional day name
|
|
51
|
+
((?<day_name1>#{DAY_NAMES})
|
|
52
|
+
[ ]
|
|
53
|
+
)?
|
|
54
|
+
(?<month_name1>#{MONTH_NAMES})
|
|
55
|
+
[ ]
|
|
56
|
+
(?<day1>\d{1,2})
|
|
57
|
+
## optional year
|
|
58
|
+
( ,? # optional comma
|
|
59
|
+
[ ]
|
|
60
|
+
(?<year1>\d{4})
|
|
61
|
+
)?
|
|
62
|
+
|
|
63
|
+
## support + and - (add .. or such - why??)
|
|
64
|
+
[ ]* - [ ]*
|
|
65
|
+
|
|
66
|
+
## optional day name
|
|
67
|
+
((?<day_name2>#{DAY_NAMES})
|
|
68
|
+
[ ]
|
|
69
|
+
)?
|
|
70
|
+
(?<month_name2>#{MONTH_NAMES})
|
|
71
|
+
[ ]
|
|
72
|
+
(?<day2>\d{1,2})
|
|
73
|
+
## optional year
|
|
74
|
+
( ,? # optional comma
|
|
75
|
+
[ ]
|
|
76
|
+
(?<year2>\d{4})
|
|
77
|
+
)?
|
|
78
|
+
)
|
|
79
|
+
\b
|
|
80
|
+
)}ix
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# FIX - remove this variant
|
|
85
|
+
# "standardize on month day [year]" !!!!
|
|
86
|
+
|
|
87
|
+
=begin
|
|
88
|
+
###
|
|
89
|
+
# variant ii
|
|
90
|
+
# e.g. 26 July - 27 July
|
|
91
|
+
# 26 July,
|
|
92
|
+
XXX_DURATION_II_RE = %r{
|
|
93
|
+
(?<duration>
|
|
94
|
+
\b
|
|
95
|
+
(?
|
|
96
|
+
## optional day name
|
|
97
|
+
((?<day_name1>#{DAY_NAMES})
|
|
98
|
+
[ ]
|
|
99
|
+
)?
|
|
100
|
+
(?<day1>\d{1,2})
|
|
101
|
+
[ ]
|
|
102
|
+
(?<month_name1>#{MONTH_NAMES})
|
|
103
|
+
## optional year
|
|
104
|
+
(
|
|
105
|
+
[ ]
|
|
106
|
+
(?<year1>\d{4})
|
|
107
|
+
)?
|
|
108
|
+
|
|
109
|
+
## support + and - (add .. or such - why??)
|
|
110
|
+
[ ]*[-][ ]*
|
|
111
|
+
|
|
112
|
+
## optional day name
|
|
113
|
+
((?<day_name2>#{DAY_NAMES})
|
|
114
|
+
[ ]
|
|
115
|
+
)?
|
|
116
|
+
(?<day2>\d{1,2})
|
|
117
|
+
[ ]
|
|
118
|
+
(?<month_name2>#{MONTH_NAMES})
|
|
119
|
+
## optional year
|
|
120
|
+
( [ ]
|
|
121
|
+
(?<year2>\d{4})
|
|
122
|
+
)?
|
|
123
|
+
)
|
|
124
|
+
\b
|
|
125
|
+
)}ix
|
|
126
|
+
=end
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# variant ii
|
|
130
|
+
# add support for shorthand
|
|
131
|
+
# August 16-18, 2011
|
|
132
|
+
# September 13-15, 2011
|
|
133
|
+
# October 18-20, 2011
|
|
134
|
+
# March 6-8 2012
|
|
135
|
+
# March 6-8
|
|
136
|
+
#
|
|
137
|
+
# - add support for August 16+17 or such (and check 16+18)
|
|
138
|
+
# use <op> to check if day2 is a plus or range or such - why? why not?
|
|
139
|
+
|
|
140
|
+
DURATION_II_RE = %r{
|
|
141
|
+
(?<duration>
|
|
142
|
+
\b
|
|
143
|
+
(?:
|
|
144
|
+
(?<month_name1>#{MONTH_NAMES})
|
|
145
|
+
[ ]
|
|
146
|
+
(?<day1>\d{1,2})
|
|
147
|
+
-
|
|
148
|
+
(?<day2>\d{1,2})
|
|
149
|
+
(?:
|
|
150
|
+
,? ## optional comma
|
|
151
|
+
[ ]
|
|
152
|
+
(?<year1>\d{4})
|
|
153
|
+
)? ## optional year
|
|
154
|
+
)
|
|
155
|
+
\b
|
|
156
|
+
)}ix
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
#############################################
|
|
161
|
+
# map tables
|
|
162
|
+
# note: order matters; first come-first matched/served
|
|
163
|
+
DURATION_RE = Regexp.union(
|
|
164
|
+
DURATION_I_RE,
|
|
165
|
+
DURATION_II_RE,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
end # class Lexer
|
|
171
|
+
end # module Fbtxt
|