fbtxt-lexer 0.0.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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +3 -0
  3. data/Manifest.txt +47 -0
  4. data/README.md +18 -0
  5. data/Rakefile +30 -0
  6. data/lib/fbtxt/lexer/debuggable.rb +58 -0
  7. data/lib/fbtxt/lexer/lexer-logger.rb +20 -0
  8. data/lib/fbtxt/lexer/lexer-on_goal.rb +167 -0
  9. data/lib/fbtxt/lexer/lexer-on_group_def.rb +31 -0
  10. data/lib/fbtxt/lexer/lexer-on_prop_cards.rb +61 -0
  11. data/lib/fbtxt/lexer/lexer-on_prop_lineup.rb +82 -0
  12. data/lib/fbtxt/lexer/lexer-on_prop_misc.rb +108 -0
  13. data/lib/fbtxt/lexer/lexer-on_prop_penalties.rb +44 -0
  14. data/lib/fbtxt/lexer/lexer-on_round_def.rb +37 -0
  15. data/lib/fbtxt/lexer/lexer-on_top.rb +133 -0
  16. data/lib/fbtxt/lexer/lexer-prep_doc.rb +131 -0
  17. data/lib/fbtxt/lexer/lexer-prep_line.rb +63 -0
  18. data/lib/fbtxt/lexer/lexer-props.rb +66 -0
  19. data/lib/fbtxt/lexer/lexer-tokenize_line.rb +381 -0
  20. data/lib/fbtxt/lexer/lexer-tokenize_norm.rb +93 -0
  21. data/lib/fbtxt/lexer/lexer.rb +192 -0
  22. data/lib/fbtxt/lexer/lexer_buffer.rb +68 -0
  23. data/lib/fbtxt/lexer/lexer_context.rb +70 -0
  24. data/lib/fbtxt/lexer/lexer_token.rb +127 -0
  25. data/lib/fbtxt/lexer/token-date--helpers.rb +130 -0
  26. data/lib/fbtxt/lexer/token-date--names.rb +108 -0
  27. data/lib/fbtxt/lexer/token-date.rb +200 -0
  28. data/lib/fbtxt/lexer/token-date_duration.rb +171 -0
  29. data/lib/fbtxt/lexer/token-geo.rb +173 -0
  30. data/lib/fbtxt/lexer/token-goals--helpers.rb +114 -0
  31. data/lib/fbtxt/lexer/token-goals.rb +306 -0
  32. data/lib/fbtxt/lexer/token-group.rb +29 -0
  33. data/lib/fbtxt/lexer/token-note.rb +40 -0
  34. data/lib/fbtxt/lexer/token-prop.rb +334 -0
  35. data/lib/fbtxt/lexer/token-prop_name.rb +83 -0
  36. data/lib/fbtxt/lexer/token-round.rb +88 -0
  37. data/lib/fbtxt/lexer/token-score--helpers.rb +189 -0
  38. data/lib/fbtxt/lexer/token-score.rb +60 -0
  39. data/lib/fbtxt/lexer/token-score_full.rb +331 -0
  40. data/lib/fbtxt/lexer/token-score_fuller.rb +434 -0
  41. data/lib/fbtxt/lexer/token-score_legs.rb +59 -0
  42. data/lib/fbtxt/lexer/token-status.rb +192 -0
  43. data/lib/fbtxt/lexer/token-status_inline.rb +112 -0
  44. data/lib/fbtxt/lexer/token-text.rb +221 -0
  45. data/lib/fbtxt/lexer/token-time.rb +144 -0
  46. data/lib/fbtxt/lexer/token.rb +224 -0
  47. data/lib/fbtxt/lexer/version.rb +24 -0
  48. data/lib/fbtxt/lexer.rb +118 -0
  49. metadata +142 -0
@@ -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
@@ -0,0 +1,173 @@
1
+ module Fbtxt
2
+ class Lexer
3
+
4
+
5
+ ##
6
+ # allow Cote'd Ivoir or such
7
+ ## e.g. add '
8
+
9
+ ## allow Ta' Qali !!!
10
+
11
+
12
+ ## todo/fix - make geo text regex more generic
13
+ ## only care about two space rule
14
+
15
+
16
+ ##
17
+ ## before with optional space
18
+ ## trying to use "hard" (joiner) space
19
+ =begin
20
+ (?:
21
+ [ ]? # only single (inline) space allowed - double spaces are breaks!!!
22
+ (?:
23
+ \p{L} | \d | [.&'°]
24
+ |
25
+ (?: (?<! [ ]) ## no space allowed before (but possible after)
26
+ [-]
27
+ )
28
+ |
29
+ (?: (?<! [ ]) ## no spaces allowed around these characters
30
+ [_/]
31
+ (?! [ ])
32
+ )
33
+ )+
34
+ =end
35
+
36
+ ## positive lookbehind - for now space (or beginning of line - for testing) only
37
+ ## (MUST be fixed number of chars - no quantifier e.g. +? etc.)
38
+ GEO_LEFT_BOUNDARY_ = '(?<= [ ,›>\[\]]|^)'
39
+ ## add lookahead/lookbehind
40
+ ## must be space!!!
41
+ ## (or comma or start/end of string)
42
+ ## kind of \b !!!
43
+ ## POSITIVE lookahead
44
+ GEO_RIGHT_BOUNDARY_ = '(?= [ ,›>\[\]]|$)'
45
+
46
+
47
+
48
+ GEO_TEXT_RE = %r{
49
+ ## must start with alpha (allow unicode letters!!)
50
+ (?<text>
51
+ #{GEO_LEFT_BOUNDARY_}
52
+ (?:
53
+ (?:
54
+ # opt 1 - start with alpha
55
+ # note - allow (dots)
56
+ \p{L}[\p{L}'.]* ## all unicode letters (e.g. [a-z])
57
+ |
58
+ # opt 2 - start with num!! -
59
+ \d+ # check for num lookahead (MUST be space or dot)
60
+ ## MAY be followed by (optional space) !
61
+ ## MUST be follow by a to z!!!!
62
+ [ ]? ## make space optional too - why? why not?
63
+ ## yes - eg. 1st, 2nd, 5th etc.
64
+ \p{L}[\p{L}.]*
65
+ |
66
+ ## opt 3 - add another weirdo case
67
+ ## e.g. 's Gravenwezel-Schilde
68
+ ## add more letters (or sequences here - why? why not?)
69
+ ## or hard-code simly 's for now - why? why not?
70
+ ' \p{L}[\p{L}.]*
71
+ )
72
+
73
+ ##
74
+ ## todo/check - find a different "more intuitive" regex/rule if possible?
75
+ ## for single spaces only
76
+ ## | [_] ## no space allowed around - keep (why? why not?)
77
+
78
+
79
+ (?:
80
+ (?:
81
+ [ ]? [&/-] [ ]? ## note - yes, allow space before and after
82
+ | [ ] # only single (inline) space allowed - double spaces are breaks!!!
83
+ )
84
+
85
+ (?:
86
+ ## followed by word (incl. specials .°' for now)
87
+ [\p{L}\d.°']+
88
+ ## todo/fix - possible in regex here
89
+ ## only end in alphanum a-z0-9 (not dot or & ???)
90
+
91
+ ## or
92
+ ## parenthesis enclosed closed text
93
+ ## e.g. Dublin (Dalymount Park)
94
+ ## Bucuresti (23 August)
95
+ ## Paris (Parc des Princes)
96
+ ## Ost-Berlin (Walter-Ulbricht)
97
+ ## Athinai (OAKA - Maroussi)
98
+ ##
99
+ ## or Valencia (Spain) or Solna
100
+ | \(
101
+ [^()\[\],;:›<>]+ ## todo - add more special chars
102
+ ## maybe list only allowed ones??
103
+ ## make pattern more strict - why? why not?
104
+ \)
105
+ )
106
+ )*
107
+ )
108
+ #{GEO_RIGHT_BOUNDARY_}
109
+ )
110
+ }ix
111
+
112
+
113
+
114
+
115
+
116
+
117
+ ## note - add "hacky" check for comma that is followed by a prop(erty)
118
+ ##
119
+ ## make sure to NOT match
120
+ ## props e.g. att: 18000
121
+ ## July 10 @ Paris, Parc des Princes, att: 18000
122
+ ## July 10 @ Paris, Parc des Princes, att: 18000
123
+ ##
124
+
125
+
126
+ GEO_END_RE = %r{
127
+ (?<geo_end>
128
+ ,
129
+ )
130
+ ## POSITIVE lookahead for props
131
+ ## todo/fix - use generic [a-z]+ - why? why not?
132
+ (?=
133
+ [ ]* ## optional spaces
134
+ (?: attendance|att
135
+ | referee?s|refs?
136
+ )
137
+ :
138
+ )
139
+ }ix
140
+
141
+
142
+
143
+
144
+ GEO_RE = Regexp.union(
145
+ SPACES_RE,
146
+ GEO_END_RE,
147
+ GEO_TEXT_RE,
148
+ / (?<sym> [,›>\[▪] ) /x,
149
+ ANY_RE,
150
+ )
151
+
152
+
153
+
154
+ ###
155
+ ## helper for testing regex match for geo names
156
+
157
+ def self._parse_geo( str )
158
+ ## note - strip - leading/trailing spaces
159
+ m = GEO_TEXT_RE.match( str.strip )
160
+ if m && m.pre_match == '' && m.post_match == ''
161
+ m
162
+ elsif m
163
+ ## note - match BUT not anchored to start and end-of-string!!!
164
+ ## report, error somehow??
165
+ nil
166
+ else
167
+ nil ## no match - return nil
168
+ end
169
+ end
170
+
171
+
172
+ end # class Lexer
173
+ end # module Fbtxt
@@ -0,0 +1,114 @@
1
+ module Fbtxt
2
+ class Lexer
3
+
4
+
5
+
6
+ def self._build_goal_minute( m )
7
+ minute = {}
8
+
9
+ minute[:m] = m[:value].to_i(10) ## always required
10
+
11
+ ## stoppage/injury time (offset)
12
+ minute[:offset] = m[:value2].to_i(10) if m[:value2]
13
+
14
+ minute[:og] = true if m[:og]
15
+ minute[:pen] = true if m[:pen]
16
+ minute[:freekick] = true if m[:fk]
17
+ minute[:header] = true if m[:hdr]
18
+
19
+ minute[:secs] = m[:secs].to_i(10) if m[:secs]
20
+
21
+ minute
22
+ end
23
+
24
+ def self._build_goal_minute_na( m )
25
+ minute = {}
26
+
27
+ minute[:m] = '?' ## or use nil or 999 or -1 or ???
28
+
29
+ minute[:og] = true if m[:og]
30
+ minute[:pen] = true if m[:pen]
31
+ minute[:freekick] = true if m[:fk]
32
+ minute[:header] = true if m[:hdr]
33
+
34
+ minute
35
+ end
36
+
37
+
38
+
39
+ def self._build_minute( m )
40
+ minute = {}
41
+ minute[:m] = m[:value].to_i(10) ## always required
42
+
43
+ ## stoppage/injury time (offset)
44
+ minute[:offset] = m[:value2].to_i(10) if m[:value2]
45
+
46
+ minute
47
+ end
48
+
49
+
50
+ def self._build_goal_count( m )
51
+ count = {}
52
+ count[:count] = m[:value].to_i(10) if m[:value]
53
+ count[:og] = m[:og_value] ? m[:og_value].to_i(10) : 1 if m[:og] ## check flag
54
+ count[:pen] = m[:pen_value] ? m[:pen_value].to_i(10) : 1 if m[:pen] ## check flag
55
+ count
56
+ end
57
+
58
+ def self._build_goal_type( m )
59
+ goal = {}
60
+ goal[:og] = true if m[:og]
61
+ goal[:pen] = true if m[:pen]
62
+ goal[:freekick] = true if m[:fk]
63
+ goal[:header] = true if m[:hdr]
64
+ goal
65
+ end
66
+
67
+
68
+ def _build_goal_minute( m ) self.class._build_goal_minute( m ); end
69
+ def _build_goal_minute_na( m ) self.class._build_goal_minute_na( m ); end
70
+ def _build_minute( m ) self.class._build_minute( m ); end
71
+ def _build_goal_count( m ) self.class._build_goal_count( m ); end
72
+ def _build_goal_type( m ) self.class._build_goal_type( m ); end
73
+
74
+
75
+
76
+
77
+
78
+ ###
79
+ # parse helpers
80
+
81
+ def self._parse_goal_minute( str )
82
+ ## note - strip - leading/trailing spaces
83
+ m = GOAL_MINUTE_RE.match( str.strip )
84
+ if m && m.pre_match == '' && m.post_match == ''
85
+ _build_goal_minute( m )
86
+ elsif m
87
+ ## note - match BUT not anchored to start and end-of-string!!!
88
+ ## report, error somehow??
89
+ nil
90
+ else
91
+ nil ## no match - return nil
92
+ end
93
+ end
94
+
95
+ def self._parse_goal_count( str )
96
+ ## note - strip - leading/trailing spaces
97
+ m = GOAL_COUNT_RE.match( str.strip )
98
+ if m && m.pre_match == '' && m.post_match == ''
99
+ _build_goal_count( m )
100
+ elsif m
101
+ ## note - match BUT not anchored to start and end-of-string!!!
102
+ ## report, error somehow??
103
+ nil
104
+ else
105
+ nil ## no match - return nil
106
+ end
107
+ end
108
+
109
+
110
+
111
+
112
+
113
+ end # class Lexer
114
+ end # module Fbtxt