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,309 @@
|
|
|
1
|
+
###
|
|
2
|
+
## team prop mode e.g.
|
|
3
|
+
##
|
|
4
|
+
##
|
|
5
|
+
## Fri Jun 14 21:00 @ München Fußball Arena, München
|
|
6
|
+
## Germany v Scotland 5-1 (3-0)
|
|
7
|
+
## (Wirtz 10' Musiala 19' Havertz 45+1' (pen.) Füllkrug 68' Can 90+3'; Rüdiger 87' (o.g.))
|
|
8
|
+
##
|
|
9
|
+
## Germany: Neuer - Kimmich, Rüdiger, Tah [Y], Mittelstädt - Andrich [Y] (Groß 46'),
|
|
10
|
+
## Kroos (Can 80') - Musiala (Müller 74'), Gündogan, Wirtz (Sane 63') -
|
|
11
|
+
## Havertz (Füllkrug 63')
|
|
12
|
+
## Scotland: Gunn - Porteous [R 44'], Hendry, Tierney (McKenna 78') - Ralston [Y],
|
|
13
|
+
## McTominay, McGregor (Gilmour 67'), Robertson - Christie (Shankland 82'),
|
|
14
|
+
## Adams (Hanley 46'), McGinn (McLean 67')
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
module Fbtxt
|
|
18
|
+
class Lexer
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
##############
|
|
22
|
+
# add support for props/ attributes e.g.
|
|
23
|
+
#
|
|
24
|
+
# Germany: Neuer - Kimmich, Rüdiger, Tah [Y], Mittelstädt - Andrich [Y] (46' Groß),
|
|
25
|
+
# Kroos (80' Can) - Musiala (74' Müller), Gündogan,
|
|
26
|
+
# Wirtz (63' Sane) - Havertz (63' Füllkrug)
|
|
27
|
+
# Scotland: Gunn - Porteous [R 44'], Hendry, Tierney (78' McKenna) - Ralston [Y],
|
|
28
|
+
# McTominay, McGregor (67' Gilmour), Robertson - Christie (82' Shankland),
|
|
29
|
+
# Adams (46' Hanley), McGinn (67' McLean)
|
|
30
|
+
#
|
|
31
|
+
## note: colon (:) MUST be followed by one (or more) spaces
|
|
32
|
+
## make sure mon feb 12 18:10 will not match
|
|
33
|
+
## allow 1. FC Köln etc.
|
|
34
|
+
## Mainz 05:
|
|
35
|
+
## limit to 30 chars max
|
|
36
|
+
## only allow chars incl. intl but (NOT ()[]/;)
|
|
37
|
+
##
|
|
38
|
+
##
|
|
39
|
+
## note - use special \G - Matches first matching position !!!!
|
|
40
|
+
## check for \G like backreference of regex tokens/parts if possible/available in ruby?
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## (i) starting w/ letters
|
|
45
|
+
## note - incl./allows digits (0-9)
|
|
46
|
+
## e.g. a1, a2000, etc.
|
|
47
|
+
##
|
|
48
|
+
## note - added back optional trailing dot (.) for abbrev. word !!!
|
|
49
|
+
PROP_KEY_WORD_ = %r{
|
|
50
|
+
\p{L}
|
|
51
|
+
[\p{L}\d]*
|
|
52
|
+
\.?
|
|
53
|
+
}ix
|
|
54
|
+
|
|
55
|
+
## note - incl. optional dot or numsign e.g. 1. or 1°
|
|
56
|
+
PROP_KEY_NUM_ = %r{
|
|
57
|
+
\d+
|
|
58
|
+
[.°]?
|
|
59
|
+
}ix
|
|
60
|
+
|
|
61
|
+
## e.g. 1A, 1FC etc.
|
|
62
|
+
## note - no trailing dot (.) for now - check if any cases exist in real world
|
|
63
|
+
PROP_KEY_NUMALPHA_ = %r{
|
|
64
|
+
\d+
|
|
65
|
+
\p{L}
|
|
66
|
+
[\p{L}\d]*
|
|
67
|
+
}ix
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
START_WITH_PROP_KEY_RE = %r{
|
|
74
|
+
\A ## note - MUST start line; leading spaces optional (eat-up)
|
|
75
|
+
(?<prop_key>
|
|
76
|
+
[ ]* ## optional leading spaces
|
|
77
|
+
(?<key>
|
|
78
|
+
(?:
|
|
79
|
+
## (i) starting w/ letters
|
|
80
|
+
#{PROP_KEY_WORD_}
|
|
81
|
+
|
|
82
|
+
## (ii) starting w/ number
|
|
83
|
+
## e.g. 1fc, 1a,
|
|
84
|
+
| #{PROP_KEY_NUMALPHA_}
|
|
85
|
+
## followed by optional dot) and
|
|
86
|
+
## optional space
|
|
87
|
+
## MUST be follow by letter (a to z)!!!!
|
|
88
|
+
## eg. 1[ fc], 1.[ fc], 1.[fc], etc.
|
|
89
|
+
| #{PROP_KEY_NUM_} (?= [ ]? \p{L})
|
|
90
|
+
)
|
|
91
|
+
(?:
|
|
92
|
+
## connectors - note - no dot (.), must match with abbrev word or num!!
|
|
93
|
+
(?: ## (i) single space or WITHOUT surrounding spaces!! - slash (/), dash (-)
|
|
94
|
+
## e.g. do NOT match one - two or one / two
|
|
95
|
+
## only one-two or one/two
|
|
96
|
+
|
|
97
|
+
[ /-]
|
|
98
|
+
|
|
99
|
+
## (ii) surrounded by leading or trailing optional space
|
|
100
|
+
## c & a, etc.
|
|
101
|
+
## d'ivoire, d' ivoire
|
|
102
|
+
## borusia 'gladbach etc.
|
|
103
|
+
## exclude space ' space - why? why not? (or ignore for now)
|
|
104
|
+
##
|
|
105
|
+
## check for quotes ('') - not realy supported here
|
|
106
|
+
## e.g. leading or trailing ' will NOT match
|
|
107
|
+
|
|
108
|
+
| [ ]? & [ ]?
|
|
109
|
+
| [ ]? '
|
|
110
|
+
| ' [ ]?
|
|
111
|
+
|
|
112
|
+
#### (iii)
|
|
113
|
+
## note - special "hack" to connect WITHOUT space
|
|
114
|
+
## for Union 1.FC and SKN St.Pölten or St.Pölten
|
|
115
|
+
## connects 1.FC => NUM+WORD
|
|
116
|
+
## 1°Mayo => NUM+WORD
|
|
117
|
+
## St.Pölten => ABBREV+WORD
|
|
118
|
+
##
|
|
119
|
+
## note - match WITHOUT (space) connector
|
|
120
|
+
## 1.FC (Union 1.FC Stein)
|
|
121
|
+
## [WORD: "Union"], [NUM: "1."], [WORD: "FC"]
|
|
122
|
+
## St.Pölten (SKN St.Pölten)
|
|
123
|
+
## [WORD: "SKN"], [ABBREV: "St."], [WORD: "Pölten"]
|
|
124
|
+
| (?<= [.°] )
|
|
125
|
+
(?= \p{L})
|
|
126
|
+
)
|
|
127
|
+
(?:
|
|
128
|
+
#{PROP_KEY_NUMALPHA_}
|
|
129
|
+
| #{PROP_KEY_NUM_}
|
|
130
|
+
| #{PROP_KEY_WORD_}
|
|
131
|
+
)
|
|
132
|
+
)*
|
|
133
|
+
) ## close <key> capture
|
|
134
|
+
[ ]*? ## slurp trailing spaces
|
|
135
|
+
:
|
|
136
|
+
|
|
137
|
+
## positive lookahead (must be followed by space!!)
|
|
138
|
+
## or allow end-of-line too
|
|
139
|
+
(?= [ ]+|$)
|
|
140
|
+
) ## close <prop_key> capture
|
|
141
|
+
}ix
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
################
|
|
148
|
+
## todo/check - use token for card short cuts?
|
|
149
|
+
## if m[:name] == 'Y'
|
|
150
|
+
## [:YELLOW_CARD, m[:name]]
|
|
151
|
+
## elsif m[:name] == 'R'
|
|
152
|
+
## [:RED_CARD, m[:name]]
|
|
153
|
+
## - [Y], [R], [Y/R] Yellow-Red Card
|
|
154
|
+
## check if minutes possible inside [Y 46']
|
|
155
|
+
## add [c] for captain too
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
## [c] or [C] for marking player as captain
|
|
159
|
+
## support [y ] too - or require Y - why? why not?
|
|
160
|
+
INLINE_CAPTAIN = %r{ (?<inline_captain>
|
|
161
|
+
\[ [cC] \]
|
|
162
|
+
)}x
|
|
163
|
+
|
|
164
|
+
INLINE_YELLOW = %r{ (?<inline_yellow>
|
|
165
|
+
\[ [yY]
|
|
166
|
+
## optional minute
|
|
167
|
+
(?: [ ]+
|
|
168
|
+
(?<minute> \d{1,3})
|
|
169
|
+
'?
|
|
170
|
+
(?:
|
|
171
|
+
\+
|
|
172
|
+
(?<offset>\d{1,2})
|
|
173
|
+
'?
|
|
174
|
+
)?
|
|
175
|
+
)?
|
|
176
|
+
\]
|
|
177
|
+
)}x
|
|
178
|
+
|
|
179
|
+
INLINE_RED = %r{ (?<inline_red>
|
|
180
|
+
\[ [rR]
|
|
181
|
+
## optional minute
|
|
182
|
+
(?: [ ]+
|
|
183
|
+
(?<minute> \d{1,3})
|
|
184
|
+
'?
|
|
185
|
+
(?:
|
|
186
|
+
\+
|
|
187
|
+
(?<offset>\d{1,2})
|
|
188
|
+
'?
|
|
189
|
+
)?
|
|
190
|
+
)?
|
|
191
|
+
\]
|
|
192
|
+
)}x
|
|
193
|
+
|
|
194
|
+
INLINE_YELLOW_RED = %r{ (?<inline_yellow_red>
|
|
195
|
+
\[ (?:y/r |
|
|
196
|
+
Y/R )
|
|
197
|
+
## optional minute
|
|
198
|
+
(?: [ ]+
|
|
199
|
+
(?<minute> \d{1,3})
|
|
200
|
+
'?
|
|
201
|
+
(?:
|
|
202
|
+
\+
|
|
203
|
+
(?<offset>\d{1,2})
|
|
204
|
+
'?
|
|
205
|
+
)?
|
|
206
|
+
)?
|
|
207
|
+
\]
|
|
208
|
+
)}x
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
### simple prop key for inline use e.g.
|
|
214
|
+
### Coach: or Trainer: or ... add more here later
|
|
215
|
+
|
|
216
|
+
PROP_KEY_INLINE_RE = %r{
|
|
217
|
+
\b
|
|
218
|
+
(?<prop_key> ## note: use prop_key (NOT prop_key_inline or such)
|
|
219
|
+
(?<key>
|
|
220
|
+
\p{L}+
|
|
221
|
+
)
|
|
222
|
+
## note - NO spaces allowed for key for now!!!
|
|
223
|
+
:
|
|
224
|
+
## possitive lookahead (must be followed by space!!)
|
|
225
|
+
(?=[ ]+)
|
|
226
|
+
)
|
|
227
|
+
}ix
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
## note allow underscore inline e.g.
|
|
232
|
+
## 5_000
|
|
233
|
+
## discuss/check - allow space inline (e.g. 5 000) - why? why not?
|
|
234
|
+
|
|
235
|
+
PROP_NUM_RE = %r{
|
|
236
|
+
\b
|
|
237
|
+
(?<num>
|
|
238
|
+
(?<value> [0-9]+
|
|
239
|
+
(?: _ [0-9]+)*
|
|
240
|
+
)
|
|
241
|
+
)
|
|
242
|
+
\b
|
|
243
|
+
}x
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
### todo/fix - allow more chars in enclosed name - why? why not?
|
|
247
|
+
## e.g. (') - Cote D'Ivore etc.
|
|
248
|
+
## change to PAREN_NAME or PARENTHESIS or such - why? why not?
|
|
249
|
+
ENCLOSED_NAME_RE = %r{
|
|
250
|
+
(?<enclosed_name>
|
|
251
|
+
\(
|
|
252
|
+
(?<name>
|
|
253
|
+
\p{L}+
|
|
254
|
+
(?:
|
|
255
|
+
[ ]
|
|
256
|
+
\p{L}+
|
|
257
|
+
)*
|
|
258
|
+
)
|
|
259
|
+
\)
|
|
260
|
+
)
|
|
261
|
+
}ix
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
###
|
|
267
|
+
## e.g. -; ... or
|
|
268
|
+
## None - ... or
|
|
269
|
+
CARDS_NONE_LEFT_RE = %r{ (?<cards_none_left>
|
|
270
|
+
## (i) w/ semicolon (;)
|
|
271
|
+
(?: (?: - | \bnone)
|
|
272
|
+
[ ]* ;
|
|
273
|
+
)
|
|
274
|
+
## (ii) w/ dash (-)
|
|
275
|
+
| (?: (?: ∅ | \bnone)
|
|
276
|
+
[ ]+ - ## space REQUIRED
|
|
277
|
+
(?=[ ]|\z) ## positive lookahead - speace required
|
|
278
|
+
)
|
|
279
|
+
)}ix
|
|
280
|
+
|
|
281
|
+
## e.g ... ;-
|
|
282
|
+
## or ... ; None
|
|
283
|
+
CARDS_NONE_RIGHT_RE = %r{ (?<cards_none_right>
|
|
284
|
+
## (i) w/ semicolon (;)
|
|
285
|
+
(?: ; [ ]*
|
|
286
|
+
(?: - | none\b)
|
|
287
|
+
)
|
|
288
|
+
## (ii) w/ dash (-)
|
|
289
|
+
| (?:
|
|
290
|
+
(?<=[ ]) ## positive lookbehind - space required
|
|
291
|
+
- [ ]+ ## space REQUIRED
|
|
292
|
+
(?: ∅ | none\b)
|
|
293
|
+
)
|
|
294
|
+
)}ix
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
CARDS_SEP_ALT_RE = %r{(?<cards_sep_alt>
|
|
298
|
+
(?<=[ ]) ## positive lookbehind - space required
|
|
299
|
+
-
|
|
300
|
+
(?=[ ]|\z) ## positive lookahead - speace required
|
|
301
|
+
)}x
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
end # class Lexer
|
|
309
|
+
end # module Fbtxt
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
module Fbtxt
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
## see token-text for TEXT_RE
|
|
7
|
+
## change PROP_NAME_RE to TEXT_II or TEXT_??? - why? why not?
|
|
8
|
+
### no do NO change
|
|
9
|
+
## change TEXT_RE to TEAM_RE or TEAM_NAME_RE !!!!
|
|
10
|
+
## it is NOT generic TEXT regex!!!
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
PROP_NAME_WORD_ = %r{
|
|
16
|
+
\p{L}+
|
|
17
|
+
\.? ## optional dot
|
|
18
|
+
}ix
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## todo/fix - remove support for double quotes e.g. "Rodri" - why? why not?
|
|
22
|
+
##
|
|
23
|
+
|
|
24
|
+
## name different from text (**does NOT allow number in name/text**)
|
|
25
|
+
## different from PROP_KEY too
|
|
26
|
+
PROP_NAME_RE = %r{
|
|
27
|
+
(?<prop_name>
|
|
28
|
+
\b
|
|
29
|
+
(?<name>
|
|
30
|
+
#{PROP_NAME_WORD_}
|
|
31
|
+
|
|
32
|
+
## connectors
|
|
33
|
+
(?:
|
|
34
|
+
## (i) space - only one single space allowed inline!!!
|
|
35
|
+
(?:
|
|
36
|
+
### check if negative lookbehind is redudant!!
|
|
37
|
+
## next char is \p{L} and NOT space
|
|
38
|
+
## thus double space not possible!!
|
|
39
|
+
(?<! [ ]) ## use negative lookbehind
|
|
40
|
+
[ ]
|
|
41
|
+
(?= \p{L}|['"]\p{L}) ## use lookahead
|
|
42
|
+
)
|
|
43
|
+
## (ii) support (inline) quoted name e.g. "Rodri" or such
|
|
44
|
+
| (?:
|
|
45
|
+
(?<=[ ]) ## use positive lookbehind
|
|
46
|
+
" \p{L}+ "
|
|
47
|
+
## require space here too - why? why not?
|
|
48
|
+
)
|
|
49
|
+
## (iii) dash (-)
|
|
50
|
+
| (?:
|
|
51
|
+
## use POSITIVE lookBEHIND
|
|
52
|
+
## note - allow leading dot (.) e.g. K.-H.Förster
|
|
53
|
+
## short for Karl-Heinz Förster
|
|
54
|
+
##
|
|
55
|
+
## change to negative lookBEHIND [ '"-]
|
|
56
|
+
## \p{L}\. | \p{L} - not MUST be fixed size
|
|
57
|
+
(?<=
|
|
58
|
+
[\p{L}.]
|
|
59
|
+
)
|
|
60
|
+
[-] ## must be surrounded by letters
|
|
61
|
+
## e.g. One-Two NOT
|
|
62
|
+
## One- Two or One - Two or One -Two etc.
|
|
63
|
+
(?= \p{L}) ## use lookahead
|
|
64
|
+
)
|
|
65
|
+
|
|
|
66
|
+
(?: ## flex rule for quote - allow any
|
|
67
|
+
## only check for double quotes e.g. cannot follow other ' for now - why? why not?
|
|
68
|
+
## allows rodrigez 'rodri' for example
|
|
69
|
+
(?<!') ## use negative lookbehind
|
|
70
|
+
'
|
|
71
|
+
)
|
|
72
|
+
| ## standard case with letter(s) and optional dot
|
|
73
|
+
#{PROP_NAME_WORD_}
|
|
74
|
+
)*
|
|
75
|
+
)
|
|
76
|
+
## add lookahead - must be non-alphanum
|
|
77
|
+
## add colon (:) too - why? why not?
|
|
78
|
+
(?= [ ,;\]\)]|$)
|
|
79
|
+
)}ix
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
end # class Lexer
|
|
83
|
+
end # module Fbtxt
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
module Fbtxt
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
####
|
|
5
|
+
#
|
|
6
|
+
## note - use \A (instead of ^) - \A strictly matches the start of the string.
|
|
7
|
+
##
|
|
8
|
+
## todo - add support for trailing markers e.g.
|
|
9
|
+
## ▪ Round 1 ▪▪▪▪▪▪▪▪
|
|
10
|
+
## :: Round 1 ::::::::::::
|
|
11
|
+
##
|
|
12
|
+
## check - allow without space (like in heading =Heading 1=) - why? why not?
|
|
13
|
+
## ▪Round 1▪▪▪▪▪▪▪▪
|
|
14
|
+
## ::Round 1::::::::::::
|
|
15
|
+
|
|
16
|
+
ROUND_OUTLINE_I_RE = %r{ \A
|
|
17
|
+
[ ]* ## ignore leading spaces (if any)
|
|
18
|
+
(?<round_marker>
|
|
19
|
+
[▪]{1,3} ## BLACK SMALL SQUARE e.g. ▪,▪▪,▪▪▪
|
|
20
|
+
)
|
|
21
|
+
[ ]+
|
|
22
|
+
(?<round_outline>
|
|
23
|
+
## must start with letter - why? why not?
|
|
24
|
+
### 1st round
|
|
25
|
+
## allow numbers e.g. Group A - 1
|
|
26
|
+
##
|
|
27
|
+
## note - CANNOT incl. :| !!!
|
|
28
|
+
## used for markers for defs/definitions
|
|
29
|
+
[^:|]+? ## use non-greedy
|
|
30
|
+
)
|
|
31
|
+
(?:
|
|
32
|
+
[ ]+
|
|
33
|
+
[▪]+
|
|
34
|
+
)?
|
|
35
|
+
[ ]* ## ignore trailing spaces (if any)
|
|
36
|
+
\z
|
|
37
|
+
}xi
|
|
38
|
+
|
|
39
|
+
ROUND_OUTLINE_II_RE = %r{ \A
|
|
40
|
+
[ ]* ## ignore leading spaces (if any)
|
|
41
|
+
(?<round_marker>
|
|
42
|
+
::{1,3} ## e.g. ::,:::,::::
|
|
43
|
+
)
|
|
44
|
+
[ ]+
|
|
45
|
+
(?<round_outline>
|
|
46
|
+
## must start with letter - why? why not?
|
|
47
|
+
### 1st round
|
|
48
|
+
## allow numbers e.g. Group A - 1
|
|
49
|
+
##
|
|
50
|
+
## note - CANNOT incl. :| !!!
|
|
51
|
+
## used for markers for defs/definitions
|
|
52
|
+
[^:|]+? ## use non-greedy
|
|
53
|
+
)
|
|
54
|
+
(?:
|
|
55
|
+
[ ]+
|
|
56
|
+
::+
|
|
57
|
+
)?
|
|
58
|
+
[ ]* ## ignore trailing spaces (if any)
|
|
59
|
+
\z
|
|
60
|
+
}xi
|
|
61
|
+
|
|
62
|
+
ROUND_OUTLINE_RE = Regexp.union( ROUND_OUTLINE_I_RE,
|
|
63
|
+
ROUND_OUTLINE_II_RE,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
###
|
|
68
|
+
# note - for def(initions) only one level support
|
|
69
|
+
# that is, no round outline additions possible (e.g ▪▪ 1st leg etc.)
|
|
70
|
+
ROUND_DEF_OUTLINE_RE = %r{ \A
|
|
71
|
+
[ ]* ## ignore leading spaces (if any)
|
|
72
|
+
(?: [▪] ## BLACK SMALL SQUARE
|
|
73
|
+
|
|
|
74
|
+
:: )
|
|
75
|
+
[ ]+
|
|
76
|
+
(?<round_outline>
|
|
77
|
+
[^:|]+? ## use non-greedy
|
|
78
|
+
)
|
|
79
|
+
[ ]* ## ignore trailing spaces (if any)
|
|
80
|
+
### possitive lookahead MUST be : OR |
|
|
81
|
+
(?= [:|]
|
|
82
|
+
[ ]) ## note: requires space for now after [:|] - keep - why? why not?
|
|
83
|
+
}ix
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
end # class Lexer
|
|
88
|
+
end # module Fbtxt
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
module Fbtxt
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def self._build_score( m )
|
|
6
|
+
## note - score is "generic"
|
|
7
|
+
## might be full-time (ft) or
|
|
8
|
+
## after extra-time (aet) or such
|
|
9
|
+
## or even undecided/unknown
|
|
10
|
+
## thus, use score1/score2 and NOT ft1/ft2
|
|
11
|
+
## thus, use (simply an) array e.g. [1,2]
|
|
12
|
+
## and NOT hash (table) e.g. { ft: [1,2] } !!!
|
|
13
|
+
|
|
14
|
+
score = [m[:score1].to_i(10),
|
|
15
|
+
m[:score2].to_i(10)]
|
|
16
|
+
|
|
17
|
+
score
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self._build_score_awd( m ) # score awarded (awd/awd.)
|
|
21
|
+
### note - use "generic" score for now
|
|
22
|
+
## to match A 3-0 B [awarded] etc.
|
|
23
|
+
score = [m[:score1].to_i(10),
|
|
24
|
+
m[:score2].to_i(10)]
|
|
25
|
+
## add score[:awarded] = true ???
|
|
26
|
+
## note - for now uses its own token e.g SCORE_AWD
|
|
27
|
+
score
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self._build_score_abd( m ) # score abandonded (abd/abd.)
|
|
31
|
+
### note - use "generic" score for now
|
|
32
|
+
score = [m[:score1].to_i(10),
|
|
33
|
+
m[:score2].to_i(10)]
|
|
34
|
+
## add score[:abd] = true ???
|
|
35
|
+
## note - for now uses its own token e.g SCORE_ABD
|
|
36
|
+
score
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def self._build_score_full( m )
|
|
41
|
+
score = {}
|
|
42
|
+
score[:p] = [m[:p1].to_i(10),
|
|
43
|
+
m[:p2].to_i(10)] if m[:p1] && m[:p2]
|
|
44
|
+
score[:et] = [m[:et1].to_i(10),
|
|
45
|
+
m[:et2].to_i(10)] if m[:et1] && m[:et2]
|
|
46
|
+
score[:ft] = [m[:ft1].to_i(10),
|
|
47
|
+
m[:ft2].to_i(10)] if m[:ft1] && m[:ft2]
|
|
48
|
+
score[:ht] = [m[:ht1].to_i(10),
|
|
49
|
+
m[:ht2].to_i(10)] if m[:ht1] && m[:ht2]
|
|
50
|
+
|
|
51
|
+
## add golden/silver flags
|
|
52
|
+
score[:golden] = true if m[:aetgg] ## golden goal (gg)/sudden death (sd)
|
|
53
|
+
score[:silver] = true if m[:aetsg] ## silver goal (sg)
|
|
54
|
+
|
|
55
|
+
score
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self._build_score_fuller( m )
|
|
59
|
+
score = {}
|
|
60
|
+
score[:p] = [m[:p1].to_i(10),
|
|
61
|
+
m[:p2].to_i(10)] if m[:p1] && m[:p2]
|
|
62
|
+
score[:et] = [m[:et1].to_i(10),
|
|
63
|
+
m[:et2].to_i(10)] if m[:et1] && m[:et2]
|
|
64
|
+
score[:ft] = [m[:ft1].to_i(10),
|
|
65
|
+
m[:ft2].to_i(10)] if m[:ft1] && m[:ft2]
|
|
66
|
+
score[:ht] = [m[:ht1].to_i(10),
|
|
67
|
+
m[:ht2].to_i(10)] if m[:ht1] && m[:ht2]
|
|
68
|
+
score[:agg] = [m[:agg1].to_i(10),
|
|
69
|
+
m[:agg2].to_i(10)] if m[:agg1] && m[:agg2]
|
|
70
|
+
|
|
71
|
+
if m[:away1] && m[:away2]
|
|
72
|
+
score[:away] = [m[:away1].to_i(10),
|
|
73
|
+
m[:away2].to_i(10)]
|
|
74
|
+
elsif m[:away] ## fallback if no away score; check away flag
|
|
75
|
+
score[:away] = true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
## add golden/silver flags
|
|
79
|
+
score[:golden] = true if m[:aetgg] ## golden goal (gg)/sudden death (sd)
|
|
80
|
+
score[:silver] = true if m[:aetsg] ## silver goal (sg)
|
|
81
|
+
|
|
82
|
+
score
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def self._build_score_fuller_more( m )
|
|
87
|
+
## SCORE + SCORE_FULLER_MORE
|
|
88
|
+
## note - after extra-time (aet) or full-time (ft)
|
|
89
|
+
## score may be present in SCORE!!!
|
|
90
|
+
score = {}
|
|
91
|
+
score[:p] = [m[:p1].to_i(10),
|
|
92
|
+
m[:p2].to_i(10)] if m[:p1] && m[:p2]
|
|
93
|
+
score[:et] = [m[:et1].to_i(10),
|
|
94
|
+
m[:et2].to_i(10)] if m[:et1] && m[:et2]
|
|
95
|
+
score[:ft] = [m[:ft1].to_i(10),
|
|
96
|
+
m[:ft2].to_i(10)] if m[:ft1] && m[:ft2]
|
|
97
|
+
score[:ht] = [m[:ht1].to_i(10),
|
|
98
|
+
m[:ht2].to_i(10)] if m[:ht1] && m[:ht2]
|
|
99
|
+
score[:agg] = [m[:agg1].to_i(10),
|
|
100
|
+
m[:agg2].to_i(10)] if m[:agg1] && m[:agg2]
|
|
101
|
+
|
|
102
|
+
if m[:away1] && m[:away2]
|
|
103
|
+
score[:away] = [m[:away1].to_i(10),
|
|
104
|
+
m[:away2].to_i(10)]
|
|
105
|
+
elsif m[:away] ## fallback if no away score; check away flag
|
|
106
|
+
score[:away] = true
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
## add golden/silver flags
|
|
110
|
+
score[:golden] = true if m[:aetgg] ## golden goal (gg)/sudden death (sd)
|
|
111
|
+
score[:silver] = true if m[:aetsg] ## silver goal (sg)
|
|
112
|
+
|
|
113
|
+
## add flag in score for et/ft/ht
|
|
114
|
+
## used for "dangling" (generic) score
|
|
115
|
+
score[:score] = 'et' if m[:aet] || m[:aetgg] || m[:aetsg]
|
|
116
|
+
score[:score] = 'ft' if m[:ft]
|
|
117
|
+
score[:score] = 'ht' if m[:ht]
|
|
118
|
+
|
|
119
|
+
score
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def self._build_score_legs( m )
|
|
124
|
+
legs = {}
|
|
125
|
+
|
|
126
|
+
############
|
|
127
|
+
### build leg1 (score)
|
|
128
|
+
score = {}
|
|
129
|
+
score[:ft] = [m[:leg1_ft1].to_i(10),
|
|
130
|
+
m[:leg1_ft2].to_i(10)]
|
|
131
|
+
legs['leg1'] = score
|
|
132
|
+
|
|
133
|
+
##################
|
|
134
|
+
### build leg2 (score)
|
|
135
|
+
score = {}
|
|
136
|
+
score[:ft] = [m[:leg2_ft1].to_i(10),
|
|
137
|
+
m[:leg2_ft2].to_i(10)] if m[:leg2_ft1] && m[:leg2_ft2]
|
|
138
|
+
score[:et] = [m[:leg2_et1].to_i(10),
|
|
139
|
+
m[:leg2_et2].to_i(10)] if m[:leg2_et1] && m[:leg2_et2]
|
|
140
|
+
score[:p] = [m[:leg2_p1].to_i(10),
|
|
141
|
+
m[:leg2_p2].to_i(10)] if m[:leg2_p1] && m[:leg2_p2]
|
|
142
|
+
legs['leg2'] = score
|
|
143
|
+
|
|
144
|
+
## check for (opt) aggregate - keep on "top-level"
|
|
145
|
+
legs[:agg] = [m[:agg1].to_i(10),
|
|
146
|
+
m[:agg2].to_i(10)] if m[:agg1] && m[:agg2]
|
|
147
|
+
legs[:away] = true if m[:away]
|
|
148
|
+
|
|
149
|
+
legs
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _build_score( m ) self.class._build_score( m ); end
|
|
154
|
+
def _build_score_awd( m ) self.class._build_score_awd( m ); end
|
|
155
|
+
def _build_score_abd( m ) self.class._build_score_abd( m ); end
|
|
156
|
+
def _build_score_full( m ) self.class._build_score_full( m ); end
|
|
157
|
+
def _build_score_fuller( m ) self.class._build_score_fuller( m ); end
|
|
158
|
+
def _build_score_fuller_more( m ) self.class._build_score_fuller_more( m ); end
|
|
159
|
+
def _build_score_legs( m ) self.class._build_score_legs( m ); end
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
###
|
|
165
|
+
## add parser helpers
|
|
166
|
+
|
|
167
|
+
def self._parse_score_full( str )
|
|
168
|
+
## note - strip - leading/trailing spaces automatic - why? why not?
|
|
169
|
+
|
|
170
|
+
m = Regexp.union(
|
|
171
|
+
SCORE_FULL_1ST_RE,
|
|
172
|
+
SCORE_FULL_RE ).match( str.strip )
|
|
173
|
+
|
|
174
|
+
if m && m.pre_match == '' && m.post_match == ''
|
|
175
|
+
pp m
|
|
176
|
+
_build_score_full( m )
|
|
177
|
+
elsif m
|
|
178
|
+
## note - match BUT not anchored to start and end-of-string!!!
|
|
179
|
+
## report, error somehow??
|
|
180
|
+
nil
|
|
181
|
+
else
|
|
182
|
+
nil ## no match - return nil
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
end # class Lexer
|
|
189
|
+
end # module Fbtxt
|