fbtxt-parser 0.9.0 → 0.9.1
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 +1 -1
- data/Manifest.txt +0 -37
- data/README.md +4 -8
- data/Rakefile +2 -1
- data/lib/fbtxt/parser/parse_tree-match.rb +3 -1
- data/lib/fbtxt/parser/parse_tree-props.rb +39 -10
- data/lib/fbtxt/parser/parser-top.rb +0 -9
- data/lib/fbtxt/parser/parser.rb +879 -843
- data/lib/fbtxt/parser/version.rb +1 -1
- data/lib/fbtxt/parser.rb +14 -82
- metadata +18 -41
- data/lib/fbtxt/parser/debuggable.rb +0 -53
- data/lib/fbtxt/parser/lexer-logger.rb +0 -20
- data/lib/fbtxt/parser/lexer-on_goal.rb +0 -167
- data/lib/fbtxt/parser/lexer-on_group_def.rb +0 -31
- data/lib/fbtxt/parser/lexer-on_prop_lineup.rb +0 -79
- data/lib/fbtxt/parser/lexer-on_prop_misc.rb +0 -123
- data/lib/fbtxt/parser/lexer-on_prop_penalties.rb +0 -40
- data/lib/fbtxt/parser/lexer-on_round_def.rb +0 -37
- data/lib/fbtxt/parser/lexer-on_top.rb +0 -133
- data/lib/fbtxt/parser/lexer-prep_doc.rb +0 -131
- data/lib/fbtxt/parser/lexer-prep_line.rb +0 -63
- data/lib/fbtxt/parser/lexer-tokenize.rb +0 -468
- data/lib/fbtxt/parser/lexer.rb +0 -231
- data/lib/fbtxt/parser/lexer_buffer.rb +0 -68
- data/lib/fbtxt/parser/lexer_token.rb +0 -126
- data/lib/fbtxt/parser/token-date--helpers.rb +0 -130
- data/lib/fbtxt/parser/token-date--names.rb +0 -108
- data/lib/fbtxt/parser/token-date.rb +0 -200
- data/lib/fbtxt/parser/token-date_duration.rb +0 -171
- data/lib/fbtxt/parser/token-geo.rb +0 -134
- data/lib/fbtxt/parser/token-goals--helpers.rb +0 -114
- data/lib/fbtxt/parser/token-goals.rb +0 -306
- data/lib/fbtxt/parser/token-group.rb +0 -29
- data/lib/fbtxt/parser/token-note.rb +0 -40
- data/lib/fbtxt/parser/token-prop.rb +0 -309
- data/lib/fbtxt/parser/token-prop_name.rb +0 -83
- data/lib/fbtxt/parser/token-round.rb +0 -88
- data/lib/fbtxt/parser/token-score--helpers.rb +0 -189
- data/lib/fbtxt/parser/token-score.rb +0 -60
- data/lib/fbtxt/parser/token-score_full.rb +0 -331
- data/lib/fbtxt/parser/token-score_fuller.rb +0 -434
- data/lib/fbtxt/parser/token-score_legs.rb +0 -59
- data/lib/fbtxt/parser/token-status.rb +0 -192
- data/lib/fbtxt/parser/token-status_inline.rb +0 -112
- data/lib/fbtxt/parser/token-text.rb +0 -221
- data/lib/fbtxt/parser/token-time.rb +0 -144
- data/lib/fbtxt/parser/token.rb +0 -224
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
module Fbtxt
|
|
3
|
-
|
|
4
|
-
## note - Tokens was placed inside Lexer - keep "top-level" for now inside Fbtxt
|
|
5
|
-
## for easier reuse with (new) lexer variants!!
|
|
6
|
-
|
|
7
|
-
## transforms
|
|
8
|
-
##
|
|
9
|
-
## Netherlands 1-2 (1-1) England
|
|
10
|
-
## => text => team
|
|
11
|
-
## score|vs
|
|
12
|
-
## text => team
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
## token iter/find better name
|
|
17
|
-
## e.g. TokenBuffer/Scanner or such ??
|
|
18
|
-
class Tokens
|
|
19
|
-
def initialize( tokens )
|
|
20
|
-
@tokens = tokens
|
|
21
|
-
@pos = 0
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def pos() @pos; end
|
|
25
|
-
def eos?() @pos >= @tokens.size; end
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
## pattern e.g. [:TEXT, [:VS,:SCORE], :TEXT]
|
|
31
|
-
def match?( *pattern )
|
|
32
|
-
## puts " starting match? #{pattern.inspect} @ #{@pos}"
|
|
33
|
-
pattern.each_with_index do |types,offset|
|
|
34
|
-
tok = peek(offset)
|
|
35
|
-
return false if tok.nil? ## no more tokens (cannot match)
|
|
36
|
-
|
|
37
|
-
## if single symbol wrap in array
|
|
38
|
-
types = types.is_a?(Array) ? types : [types]
|
|
39
|
-
return false unless types.include?( tok.type )
|
|
40
|
-
end
|
|
41
|
-
true
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def cur() peek(0); end
|
|
47
|
-
|
|
48
|
-
def peek(offset=1)
|
|
49
|
-
## return nil if eos
|
|
50
|
-
if @pos+offset >= @tokens.size
|
|
51
|
-
nil
|
|
52
|
-
else
|
|
53
|
-
@tokens[@pos+offset]
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def next
|
|
58
|
-
# if @pos >= @tokens.size
|
|
59
|
-
# raise ArgumentError, "end of array - #{@pos} >= #{@tokens.size}"
|
|
60
|
-
# end
|
|
61
|
-
# throw (standard) end of iteration here why? why not?
|
|
62
|
-
|
|
63
|
-
t = @tokens[@pos]
|
|
64
|
-
@pos += 1
|
|
65
|
-
t
|
|
66
|
-
end
|
|
67
|
-
end # class Tokens
|
|
68
|
-
end # module Fbtxt
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
module Fbtxt
|
|
2
|
-
class Lexer
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Token
|
|
7
|
-
|
|
8
|
-
## Token.newline( lineno: 1, offset: [1,2] )
|
|
9
|
-
## maps to =>
|
|
10
|
-
## Token.new( :NEWLINE, "\n", lineno: 1, offset: [1,2])
|
|
11
|
-
##
|
|
12
|
-
## use self.nl ?
|
|
13
|
-
def self.newline( lineno:, offset: [])
|
|
14
|
-
new( :NEWLINE, "\n", lineno: lineno, offset: offset )
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
## Token.literal( ",", lineno: 4, offset: [5,6])
|
|
18
|
-
## # maps to =>
|
|
19
|
-
## Token.new( ",", ",", lineno: 4, offset: [5,6])
|
|
20
|
-
##
|
|
21
|
-
## use self.lit?
|
|
22
|
-
def self.literal( literal, lineno:, offset: [])
|
|
23
|
-
new( literal, literal, lineno: lineno, offset: offset )
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
## or use virt or pseudo - why? why not?
|
|
27
|
-
def self.virtual( type, lineno:, offset: [])
|
|
28
|
-
## note - offset (start/end) should be same number (zero-width assertions!!)
|
|
29
|
-
## e.g. :GOALS_COMPAT, "<|GOALS_COMPAT|>"
|
|
30
|
-
new( type, '', lineno: lineno, offset: offset )
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
attr_reader :type, :text,
|
|
35
|
-
:lineno, :offset
|
|
36
|
-
|
|
37
|
-
def initialize( type, text='',
|
|
38
|
-
lineno:, offset: [],
|
|
39
|
-
value: nil )
|
|
40
|
-
@type = type
|
|
41
|
-
@text = text # note - lexeme (string from source)
|
|
42
|
-
@lineno = lineno # note - lineno (integer number - not line as string) !!!
|
|
43
|
-
|
|
44
|
-
raise TypeError, "type Array required for offset; got #{offset.inspect}" unless offset.is_a?( Array )
|
|
45
|
-
@offset = offset # note - for now char offset [start,end] in line (NOT absolute!!)
|
|
46
|
-
# maybe latter add MatchData#byteoffset instead - why? why not?
|
|
47
|
-
@value = value # might be (union of) string/array/hash
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def value
|
|
51
|
-
## note - if value is not set (nil) return text (lexeme)
|
|
52
|
-
## no need to duplicate text as value
|
|
53
|
-
@value.nil? ? @text : @value
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
## note: do NOT use as_text/text to avoid confusion with (raw) text (lexeme)
|
|
58
|
-
##
|
|
59
|
-
## use
|
|
60
|
-
## as_str -- value (as String)
|
|
61
|
-
## as_int -- value (as Integer)
|
|
62
|
-
## as_hash -- value (as Hash)
|
|
63
|
-
## as_ary -- value (as Array)
|
|
64
|
-
|
|
65
|
-
def as_str
|
|
66
|
-
raise TypeError, "token value #{@value.inspect} is #{@value.class.name} NOT string; sorry" if @value && !@value.is_a?(String)
|
|
67
|
-
## note - if value is not set (nil) return text (lexeme)
|
|
68
|
-
## no need to duplicate text as value
|
|
69
|
-
@value.nil? ? @text : @value
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def as_int
|
|
73
|
-
raise TypeError, "token value #{@value.inspect} is #{@value.class.name} NOT integer; sorry" if !@value.is_a?(Integer)
|
|
74
|
-
@value
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def as_hash
|
|
78
|
-
raise TypeError, "token value #{@value.inspect} is #{@value.class.name} NOT hash; sorry" if !@value.is_a?(Hash)
|
|
79
|
-
@value
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def as_ary
|
|
83
|
-
raise TypeError, "token value #{@value.inspect} is #{@value.class.name} NOT array; sorry" if !@value.is_a?(Array)
|
|
84
|
-
@value
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def to_legacy
|
|
89
|
-
## return old "legacy" array format
|
|
90
|
-
if @value.nil?
|
|
91
|
-
[@type, @text]
|
|
92
|
-
else
|
|
93
|
-
[@type, [@text, @value]]
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
## pretty print
|
|
99
|
-
def pretty_print( printer )
|
|
100
|
-
## check for literal e.g. "," etc.
|
|
101
|
-
if @type.is_a?( String ) && @type == @text && @value.nil?
|
|
102
|
-
printer.text( "[#{@type.inspect}" )
|
|
103
|
-
elsif @type.is_a?( Symbol ) && @text == '' && @value.nil?
|
|
104
|
-
## assume virtual token (zero-width)
|
|
105
|
-
## use <!...!> style
|
|
106
|
-
printer.text( "[<|#{@type}|>" )
|
|
107
|
-
else
|
|
108
|
-
printer.text( "[#{@type.inspect} #{@text.inspect}" )
|
|
109
|
-
printer.text( ", #{value.inspect}") if @value
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
printer.text( " @#{@lineno}" )
|
|
114
|
-
## note - for now print only start_offset (offset[0])
|
|
115
|
-
## to keep dump/output shorter
|
|
116
|
-
## note - start counting columns at one (NOT zero), thus, add +1 !!
|
|
117
|
-
printer.text( ":#{@offset[0]+1}" ) if @offset.is_a?(Array) && @offset.size == 2
|
|
118
|
-
printer.text( "]" )
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
end # class Token
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
end # class Lexer
|
|
126
|
-
end # module Fbtxt
|
|
@@ -1,130 +0,0 @@
|
|
|
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
|
|
@@ -1,108 +0,0 @@
|
|
|
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
|
|
@@ -1,200 +0,0 @@
|
|
|
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
|