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,112 @@
|
|
|
1
|
+
module Fbtxt
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
## (match) status inline versions
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## "inline" match status e.g.
|
|
10
|
+
## Clapham Rovers w/o Hitchin
|
|
11
|
+
## Queen's Park bye
|
|
12
|
+
|
|
13
|
+
## add support for WO or W-0 too - why? why not?
|
|
14
|
+
INLINE_WO_RE = %r{
|
|
15
|
+
(?<inline_wo>
|
|
16
|
+
\b (?: w/o | W/O ) \b
|
|
17
|
+
)}x ## note - NOT case insensitive
|
|
18
|
+
|
|
19
|
+
INLINE_BYE_RE = %r{
|
|
20
|
+
(?<inline_bye>
|
|
21
|
+
\b (?: bye | BYE ) \b
|
|
22
|
+
)}x ## note - NOT case insensitive
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
###
|
|
26
|
+
# A n/p B (note - basically a inline short form of A v B [cancelled] )
|
|
27
|
+
# N/P
|
|
28
|
+
INLINE_NP_RE = %r{
|
|
29
|
+
(?<inline_np>
|
|
30
|
+
\b (?: n/p | N/P ) \b
|
|
31
|
+
)}x ## note - NOT case insensitive
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
###
|
|
35
|
+
# abd/abd. or aban/aban. [abandoned]
|
|
36
|
+
# ABD/ABAN
|
|
37
|
+
INLINE_ABD_RE = %r{
|
|
38
|
+
(?<inline_abd>
|
|
39
|
+
\b (?: abd\.? |
|
|
40
|
+
aban\.? |
|
|
41
|
+
ABD | ABAN
|
|
42
|
+
)
|
|
43
|
+
## POSITIVE lookahead - requires space
|
|
44
|
+
(?= [ ])
|
|
45
|
+
)}x ## note - NOT case insensitive
|
|
46
|
+
|
|
47
|
+
####
|
|
48
|
+
# susp/susp. [suspended]
|
|
49
|
+
# SUSP
|
|
50
|
+
INLINE_SUSP_RE = %r{
|
|
51
|
+
(?<inline_susp>
|
|
52
|
+
\b (?: susp\.? |
|
|
53
|
+
SUSP )
|
|
54
|
+
## POSITIVE lookahead - requires space
|
|
55
|
+
(?= [ ])
|
|
56
|
+
)}x ## note - NOT case insensitive
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
####
|
|
60
|
+
# ppd/ppd. or pst/pst. or pstp/pstp. or postp/postp. [postponed]
|
|
61
|
+
# PPD/PSTP/POSTP/P-P
|
|
62
|
+
# todo/check - add/allow p-p too - why? why not?
|
|
63
|
+
INLINE_PPD_RE = %r{
|
|
64
|
+
(?<inline_ppd>
|
|
65
|
+
\b (?: ppd\.? |
|
|
66
|
+
pst\.? |
|
|
67
|
+
po?stp\.? |
|
|
68
|
+
PPD | PST | PO?STP | P-P
|
|
69
|
+
)
|
|
70
|
+
## POSITIVE lookahead - requires space
|
|
71
|
+
(?= [ ])
|
|
72
|
+
)}x ## note - NOT case insensitive
|
|
73
|
+
|
|
74
|
+
####
|
|
75
|
+
# void via x-x X-X
|
|
76
|
+
# todo/check - only allow X-X - why? why not?
|
|
77
|
+
INLINE_VOID_RE = %r{
|
|
78
|
+
(?<inline_void>
|
|
79
|
+
\b (?: x-x |
|
|
80
|
+
X-X
|
|
81
|
+
)
|
|
82
|
+
## POSITIVE lookahead - requires space
|
|
83
|
+
(?= [ ])
|
|
84
|
+
)}x ## note - NOT case insensitive
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
####
|
|
88
|
+
# awd/awd. [awarded]
|
|
89
|
+
# AWD
|
|
90
|
+
# note - recommendation is to allways include score
|
|
91
|
+
# thus, use/prefer SCORE_AWD e.g. 0-3 awd
|
|
92
|
+
INLINE_AWD_RE = %r{
|
|
93
|
+
(?<inline_awd>
|
|
94
|
+
\b (?: awd\.? | AWD )
|
|
95
|
+
## POSITIVE lookahead - requires space
|
|
96
|
+
(?= [ ])
|
|
97
|
+
)}x ## note - NOT case insensitive
|
|
98
|
+
|
|
99
|
+
###
|
|
100
|
+
# canc/canc. [cancelled]
|
|
101
|
+
# CANC
|
|
102
|
+
INLINE_CANC_RE = %r{
|
|
103
|
+
(?<inline_canc>
|
|
104
|
+
\b (?: canc\.? | CANC )
|
|
105
|
+
## POSITIVE lookahead - requires space
|
|
106
|
+
(?= [ ])
|
|
107
|
+
)}x ## note - NOT case insensitive
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
end # class Lexer
|
|
112
|
+
end # module Fbtxt
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
module Fbtxt
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
## todo/fix - change TEXT_RE to TEAM_RE !!!!
|
|
7
|
+
## do NOT use (anymore) as generic TEXT_RE
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## note - TEXT_RE used for TEAM_NAMES
|
|
11
|
+
## plus as "legacy" shortcut for (simple) group or round names e.g.
|
|
12
|
+
## Group A, Group 1, ..
|
|
13
|
+
## Matchday 1, 1. Round,
|
|
14
|
+
## note - no exception for (shortcut) group or round (MUST match team name pattern!)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## note - do NOT allow single alpha text for now
|
|
19
|
+
## add later?? A - B C - D - why?
|
|
20
|
+
## opt 1) one alpha
|
|
21
|
+
## (?<text_i> [a-z]) # only allow single letter text (not numbers!!)
|
|
22
|
+
|
|
23
|
+
## opt 2) more than one alphanum
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### allow special case - starting text with number e.g.
|
|
27
|
+
## number must be follow by space or dot ()
|
|
28
|
+
# 1 FC ## allow 1-FC or 1FC - why? why not?
|
|
29
|
+
# 1FC"
|
|
30
|
+
# 1. FC
|
|
31
|
+
# 1.FC
|
|
32
|
+
# 23° Noviembre
|
|
33
|
+
# 1890 Munich
|
|
34
|
+
# 1-FC - XXXX - not allowed for now, parse error
|
|
35
|
+
# 1/FC - XXXX - not allowed for now
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
##
|
|
39
|
+
# allow Cote'd Ivoir or such
|
|
40
|
+
## e.g. add '
|
|
41
|
+
|
|
42
|
+
## note:
|
|
43
|
+
## make sure these do NOT match!!!
|
|
44
|
+
## TEXT => "Matchday 1 / Group A"
|
|
45
|
+
## TEXT => "Matchday 2 / Group A"
|
|
46
|
+
## TEXT => "Matchday 3 / Group A"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
TEXT_RE = %r{
|
|
51
|
+
## must start with alpha (allow unicode letters!!)
|
|
52
|
+
(?<text>
|
|
53
|
+
## positive lookbehind
|
|
54
|
+
## (MUST be fixed number of chars - no quantifier e.g. +? etc.)
|
|
55
|
+
(?<=[ ,;@|\[\]]
|
|
56
|
+
|^
|
|
57
|
+
)
|
|
58
|
+
(?:
|
|
59
|
+
# opt 1 - start with alpha
|
|
60
|
+
\p{L}+ ## all unicode letters (e.g. [a-z])
|
|
61
|
+
|
|
|
62
|
+
|
|
63
|
+
# opt 2 - start with num!! - allow special case (e.g. 1. FC)
|
|
64
|
+
\d+ # check for num lookahead (MUST be space or dot)
|
|
65
|
+
## MUST be followed by (optional dot) and
|
|
66
|
+
## required space !!!
|
|
67
|
+
## MUST be follow by a to z!!!!
|
|
68
|
+
[.°]? ## optional dot (.) or degree(°) - todo - add number sign too!!
|
|
69
|
+
[ ]? ## make space optional too - why? why not?
|
|
70
|
+
## yes - eg. 1st, 2nd, 5th etc.
|
|
71
|
+
\p{L}+
|
|
72
|
+
|
|
|
73
|
+
## opt 3 - add another weirdo case
|
|
74
|
+
## e.g. 's Gravenwezel-Schilde
|
|
75
|
+
'[s] [ ] \p{L}+
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
(?:(?: (?:[ ] # only single spaces allowed inline!!!
|
|
80
|
+
## note - exclude (v[ ]/vs[ ]/vs.[ ])
|
|
81
|
+
## AND switch to case-sensitive (via -i!!!)
|
|
82
|
+
(?! (?-i: (?: ## note - (big) V not matching for versus!!!
|
|
83
|
+
vs\.?|v|
|
|
84
|
+
|
|
85
|
+
n/p|N/P|
|
|
86
|
+
w/o|W/O|
|
|
87
|
+
abd\.?|ABD|
|
|
88
|
+
aban\.?|ABAN|
|
|
89
|
+
susp\.?|SUSP|
|
|
90
|
+
ppd\.?|PPD|
|
|
91
|
+
pst\.?|PST|
|
|
92
|
+
po?stp\.?|PO?STP|P-P|
|
|
93
|
+
x-x|X-X|
|
|
94
|
+
awd\.?|AWD|
|
|
95
|
+
canc\.?|CANC ) [ ]
|
|
96
|
+
|
|
|
97
|
+
(?: bye|BYE ) (?:[ ]|$))
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
|
|
|
101
|
+
[/-] ## must NOT be surrounded by spaces
|
|
102
|
+
)?
|
|
103
|
+
(?:
|
|
104
|
+
\p{L}
|
|
105
|
+
|
|
|
106
|
+
(?: ## note - restrict [.&'] to single char usage (no doubled e.g. && etc.)
|
|
107
|
+
\. (?! \.) ## allow single points only (now two or more etc.)
|
|
108
|
+
|
|
|
109
|
+
& (?! &)
|
|
110
|
+
|
|
|
111
|
+
' (?! ')
|
|
112
|
+
)
|
|
113
|
+
|
|
|
114
|
+
(?:
|
|
115
|
+
\d+
|
|
116
|
+
(?!
|
|
117
|
+
[0-9h'+] | ## protected break on 12h / 12' / 1-1
|
|
118
|
+
## check usege for 3+4 - possible? where ? why?
|
|
119
|
+
(?:[.:-]\d) ## protected/exclude/break on 12.03 / 12:03 / 12-12
|
|
120
|
+
## BUT allow Park21-Arena for example e.g. 21-A :-)
|
|
121
|
+
)
|
|
122
|
+
[°]? ## followed by optional ord
|
|
123
|
+
## negative lookahead for numbers
|
|
124
|
+
## note - include digits itself!!!
|
|
125
|
+
## note - remove / (slash) e.g. allows UDI'19/Beter Bed
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
)* ## must NOT end with space or dash(-)
|
|
129
|
+
## todo/fix - possible in regex here
|
|
130
|
+
## only end in alphanum a-z0-9 (not dot or & ???)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
## allow optional at the end
|
|
134
|
+
## tag or year
|
|
135
|
+
## make it and in the future - why? why not?
|
|
136
|
+
##
|
|
137
|
+
## change - fix
|
|
138
|
+
## do NOT use (A) for amateur
|
|
139
|
+
## use A or A. with NO ()!!!
|
|
140
|
+
## (A) - allow with predined alpha only for now
|
|
141
|
+
## e.g. (A) - amateur a team or b?
|
|
142
|
+
### same for U21 or U9 etc
|
|
143
|
+
## use with NO ()!!! - why? why not?
|
|
144
|
+
## or U21 U9 etc. - why? why not?
|
|
145
|
+
## or etc.
|
|
146
|
+
## (1879-1893) or allow years e.g. (1879-1893)
|
|
147
|
+
###
|
|
148
|
+
## add allow country code three to five letters for now
|
|
149
|
+
## change to generic 1 to 5 - why? why not?
|
|
150
|
+
## e.g. (A), (I),
|
|
151
|
+
## (AUT)
|
|
152
|
+
## (TRNC) five? for UEFA code for northern cyprus
|
|
153
|
+
## change to 1 to 4 - why? why not?
|
|
154
|
+
## check - fix possible for upper case only here
|
|
155
|
+
## inline for this group only?
|
|
156
|
+
(?:
|
|
157
|
+
[ ]
|
|
158
|
+
\(
|
|
159
|
+
\d{4}-\d{4}
|
|
160
|
+
\)
|
|
161
|
+
)?
|
|
162
|
+
(?:
|
|
163
|
+
######
|
|
164
|
+
# check for country code (cc)
|
|
165
|
+
# e.g. (AUT) or ,AUT or AUT
|
|
166
|
+
(?:
|
|
167
|
+
[ ] ## note - do NOT allow more than one space!!! - why? why not?
|
|
168
|
+
\(
|
|
169
|
+
## note - auto-exclude reserved (aet) from SCORE_FULLER_MORE!!!
|
|
170
|
+
## plus golden goal (gg)/sudden death (sd), silver goal (sg)
|
|
171
|
+
## (ht), (ft)
|
|
172
|
+
(?! (?: aet | agget | asdet | asget | ht | ft )
|
|
173
|
+
\)
|
|
174
|
+
)
|
|
175
|
+
(?:
|
|
176
|
+
[A-Z]{1,5}
|
|
177
|
+
)
|
|
178
|
+
\)
|
|
179
|
+
)
|
|
180
|
+
|
|
|
181
|
+
(?:
|
|
182
|
+
[ ]*[,›>][ ]*
|
|
183
|
+
[A-Z]{1,5}
|
|
184
|
+
\b
|
|
185
|
+
)
|
|
186
|
+
)?
|
|
187
|
+
## add lookahead/lookbehind
|
|
188
|
+
## must be space!!!
|
|
189
|
+
## (or comma or start/end of string)
|
|
190
|
+
## kind of \b !!!
|
|
191
|
+
## positive lookahead
|
|
192
|
+
(?=[ ,;@|\[\]]
|
|
193
|
+
|$
|
|
194
|
+
)
|
|
195
|
+
)
|
|
196
|
+
}ix
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
###
|
|
203
|
+
## helper for testing regex match for team names
|
|
204
|
+
|
|
205
|
+
def self._parse_team( str )
|
|
206
|
+
## note - strip - leading/trailing spaces
|
|
207
|
+
m = TEXT_RE.match( str.strip )
|
|
208
|
+
if m && m.pre_match == '' && m.post_match == ''
|
|
209
|
+
m
|
|
210
|
+
elsif m
|
|
211
|
+
## note - match BUT not anchored to start and end-of-string!!!
|
|
212
|
+
## report, error somehow??
|
|
213
|
+
nil
|
|
214
|
+
else
|
|
215
|
+
nil ## no match - return nil
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
end # class Lexer
|
|
221
|
+
end # module Fbtxt
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
module Fbtxt
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# keep 18h30 - why? why not?
|
|
8
|
+
# add support for 6:30pm 8:20am etc. - why? why not?
|
|
9
|
+
#
|
|
10
|
+
# check - only support h e.g. 18h30 or 18H30 too - why? why not?
|
|
11
|
+
# e.g. 18:30 (or 18h30)
|
|
12
|
+
# note - optional timezone possible e.g.
|
|
13
|
+
# 18:30 UTC+1 or 18:30 BST/UTC+1 or such!!!
|
|
14
|
+
# 18:30 UTC+01 or 18:30 BST/UTC+01
|
|
15
|
+
#
|
|
16
|
+
#
|
|
17
|
+
# note 18.30 no longer supported - MUST use 18:30 or 18h30 !!!
|
|
18
|
+
#
|
|
19
|
+
#
|
|
20
|
+
#
|
|
21
|
+
# note - local time is now (inline) part of time!!!
|
|
22
|
+
# and, thus, must always follow time
|
|
23
|
+
# e.g. 18:30 (19:30 BST)
|
|
24
|
+
#
|
|
25
|
+
## local time e.g (19:30 UTC+1) or (19:30 BST/UTC+1) or
|
|
26
|
+
## note - timezone is optional! e.g. (19:30) works too
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
TIME_RE = %r{
|
|
30
|
+
\b
|
|
31
|
+
(?<time>
|
|
32
|
+
(?<hour>\d{1,2})
|
|
33
|
+
[:h]
|
|
34
|
+
(?<minute>\d{2})
|
|
35
|
+
|
|
36
|
+
#### optional (inline) timezone
|
|
37
|
+
## note - non-utc timezone MUST be hard-coded (added) here!!!
|
|
38
|
+
## avoids eating-up team names (separated by one space)
|
|
39
|
+
## e.g. 18:30 MEX v MEX
|
|
40
|
+
(?:
|
|
41
|
+
[ ] ## require space - why? why not
|
|
42
|
+
(?<timezone>
|
|
43
|
+
(?:
|
|
44
|
+
## GMT - Greenwich Mean Time
|
|
45
|
+
## BST - British Summer Time
|
|
46
|
+
## CES?T - Central European (Summer) Time
|
|
47
|
+
## EES?T - Eastern European (Summer) Time
|
|
48
|
+
##
|
|
49
|
+
(?: GMT|BST|CES?T|EES?T)
|
|
50
|
+
(?: /
|
|
51
|
+
UTC (?: [+-]\d{1,4} | ±0)
|
|
52
|
+
)?
|
|
53
|
+
)
|
|
54
|
+
|
|
|
55
|
+
(?:
|
|
56
|
+
UTC (?: [+-]\d{1,4} | ±0)
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
)?
|
|
60
|
+
)
|
|
61
|
+
\b
|
|
62
|
+
|
|
63
|
+
####
|
|
64
|
+
### note - local time is now INLINE and MUST follow time
|
|
65
|
+
(?:
|
|
66
|
+
[ ]+ ## todo/check - make space optional - why? why not?
|
|
67
|
+
\(
|
|
68
|
+
(?<time_local>
|
|
69
|
+
(?<local_hour>\d{1,2})
|
|
70
|
+
[:h] ### todo/fix - MUST match style in time above!!!
|
|
71
|
+
### use capture with backref!!!!
|
|
72
|
+
(?<local_minute>\d{2})
|
|
73
|
+
|
|
74
|
+
####
|
|
75
|
+
## optional "local" timezone name eg. BRT or CEST etc.
|
|
76
|
+
(?:
|
|
77
|
+
[ ] ## require space - why? why not
|
|
78
|
+
(?<local_timezone>
|
|
79
|
+
(?: [A-Z]{3,4}
|
|
80
|
+
(?: /
|
|
81
|
+
UTC (?: [+-]\d{1,4} | ±0)
|
|
82
|
+
)?
|
|
83
|
+
)
|
|
84
|
+
|
|
|
85
|
+
(?: ## e.g. 0 or 00 or 0000
|
|
86
|
+
UTC (?: [+-]\d{1,4} | ±0)
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
)? # note - make timezone optional!!!
|
|
90
|
+
)
|
|
91
|
+
\)
|
|
92
|
+
)?
|
|
93
|
+
}ix
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def self._build_time( m )
|
|
97
|
+
## unify to iso-format
|
|
98
|
+
### 12.40 => 12:40
|
|
99
|
+
## 12h40 => 12:40 etc.
|
|
100
|
+
## keep string (no time-only type in ruby)
|
|
101
|
+
data = { time: {} }
|
|
102
|
+
|
|
103
|
+
hour = m[:hour].to_i(10) ## allow 08/07/etc.
|
|
104
|
+
minute = m[:minute].to_i(10)
|
|
105
|
+
|
|
106
|
+
## check if 24:00 possible? or only 0:00 (23:59)
|
|
107
|
+
unless (hour >=0 && hour <=23) &&
|
|
108
|
+
(minute >=0 && minute <=59)
|
|
109
|
+
raise ArgumentError, "parse error - time >#{m[:time]}< out-of-range"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
data[:time][:h] = hour
|
|
113
|
+
data[:time][:m] = minute
|
|
114
|
+
data[:time][:timezone] = m[:timezone] if m[:timezone]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
## check if local time present e.g.
|
|
118
|
+
## 18:30 (19:30)
|
|
119
|
+
## 18:30 (19:30 BST) etc.
|
|
120
|
+
if m[:time_local]
|
|
121
|
+
data[:time_local] = {}
|
|
122
|
+
|
|
123
|
+
local_hour = m[:local_hour].to_i(10) ## allow 08/07/etc.
|
|
124
|
+
local_minute = m[:local_minute].to_i(10)
|
|
125
|
+
|
|
126
|
+
## check if 24:00 possible? or only 0:00 (23:59)
|
|
127
|
+
unless (hour >=0 && hour <=23) &&
|
|
128
|
+
(minute >=0 && minute <=59)
|
|
129
|
+
raise ArgumentError, "parse error - local time >#{m[:time_local]}< out-of-range"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
data[:time_local][:h] = local_hour
|
|
133
|
+
data[:time_local][:m] = local_minute
|
|
134
|
+
data[:time_local][:timezone] = m[:local_timezone] if m[:local_timezone]
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
data
|
|
138
|
+
end
|
|
139
|
+
def _build_time(m) self.class._build_time(m); end
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
end # class Lexer
|
|
144
|
+
end # module Fbtxt
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
module Fbtxt
|
|
4
|
+
class Lexer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
###
|
|
9
|
+
## add att(endance) e.g. att: 18000
|
|
10
|
+
##
|
|
11
|
+
## A v B 2-1 att: 18000
|
|
12
|
+
|
|
13
|
+
ATTENDANCE_RE = %r{
|
|
14
|
+
(?<attendance>
|
|
15
|
+
\b
|
|
16
|
+
(?: attendance|att )
|
|
17
|
+
: [ ]*
|
|
18
|
+
(?<value>
|
|
19
|
+
[1-9]
|
|
20
|
+
(?: _? \d+ )*
|
|
21
|
+
)
|
|
22
|
+
\b
|
|
23
|
+
)}ix
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
###
|
|
29
|
+
## home/away/neutral - (h), (a), (n)
|
|
30
|
+
## add support for h/a/n
|
|
31
|
+
## with (?-i \b [han] \b) lower-case and \b boundry - why? why not?
|
|
32
|
+
|
|
33
|
+
TEAM_HOME_RE = %r{ (?<team_home> \(h\) )}ix
|
|
34
|
+
TEAM_AWAY_RE = %r{ (?<team_away> \(a\) )}ix
|
|
35
|
+
TEAM_NEUTRAL_RE = %r{ (?<team_neutral> \(n\) )}ix
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
##
|
|
42
|
+
## note VS
|
|
43
|
+
## remove VS for now
|
|
44
|
+
## e.g. Olympia Wijgmaal v VS Kortenaken
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## note - only match case sensitive (downcased letters)!!!
|
|
49
|
+
## note - bigger match first e.g. vs than v etc.
|
|
50
|
+
VS_RE = %r{
|
|
51
|
+
(?<vs>
|
|
52
|
+
(?<=[ ]) # positive lookBEHIND for space
|
|
53
|
+
(?-i:
|
|
54
|
+
vs\.?|v
|
|
55
|
+
)
|
|
56
|
+
(?=[ ]) # positive lookAHEAD for space
|
|
57
|
+
)
|
|
58
|
+
}ix
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
##
|
|
62
|
+
## ▪SF or ▪1,▪17, etc.
|
|
63
|
+
## note - only numbers and upcase allowed
|
|
64
|
+
## limited to two-letters for now - make more generic - why? why not?
|
|
65
|
+
## may add SF1, SF2, or such later !!!
|
|
66
|
+
INLINE_ROUND_SHORT_RE = %r{
|
|
67
|
+
(?<inline_round_short>
|
|
68
|
+
▪
|
|
69
|
+
(?<inline_round_text>
|
|
70
|
+
[0-9]+
|
|
71
|
+
| [A-Z]{1,2} [0-9]*
|
|
72
|
+
)
|
|
73
|
+
(?= [ ]|$) # positive lookAHEAD for space (or end-of-line)
|
|
74
|
+
)}x
|
|
75
|
+
|
|
76
|
+
###
|
|
77
|
+
## ▪ Replay
|
|
78
|
+
## ▪ 1st Leg
|
|
79
|
+
INLINE_ROUND_BIG_RE = %r{
|
|
80
|
+
(?<inline_round_big>
|
|
81
|
+
▪ [ ]
|
|
82
|
+
(?<inline_round_text>
|
|
83
|
+
[^\[\(@]+? ## note - non-greedy
|
|
84
|
+
## allow commas (,) or slash(/) - why? why not?
|
|
85
|
+
)
|
|
86
|
+
(?= [ ]{2}|$) # positive lookAHEAD for TWO(!) spaces (or end-of-line)
|
|
87
|
+
)}x
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
##############
|
|
93
|
+
## "top-level" regex used for:
|
|
94
|
+
## - date_header
|
|
95
|
+
## - match_header & match_line_more
|
|
96
|
+
## - match_line
|
|
97
|
+
|
|
98
|
+
RE = Regexp.union(
|
|
99
|
+
SPACES_RE,
|
|
100
|
+
|
|
101
|
+
INLINE_ROUND_SHORT_RE,
|
|
102
|
+
INLINE_ROUND_BIG_RE,
|
|
103
|
+
|
|
104
|
+
STATUS_RE, ## match status e.g. [cancelled], etc.
|
|
105
|
+
|
|
106
|
+
INLINE_WO_RE, ## (inline) match status - w/o (walkout)
|
|
107
|
+
INLINE_NP_RE, ## (inline) match status - n/p (not played)
|
|
108
|
+
INLINE_BYE_RE, ## (inline) match status - bye (advance to next round)
|
|
109
|
+
INLINE_ABD_RE, ## (inline) match status - abd/abd. (abandoned)
|
|
110
|
+
INLINE_SUSP_RE, ## (inline) match status - susp/susp. (suspended)
|
|
111
|
+
INLINE_PPD_RE, ## (inline) match status - ppd/ppd. or pstp/pstp. or postp/postp. or p-p (postponed)
|
|
112
|
+
INLINE_VOID_RE, ## (inline) match status - x-x (voided)
|
|
113
|
+
INLINE_AWD_RE, ## (inline) match status - awd/awd. (awarded)
|
|
114
|
+
INLINE_CANC_RE, ## (inline) match status - canc/canc. (cancelled/canceled)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
TEAM_HOME_RE, ## (H)
|
|
118
|
+
TEAM_AWAY_RE, ## (A)
|
|
119
|
+
TEAM_NEUTRAL_RE, ## (N)
|
|
120
|
+
|
|
121
|
+
NOTE_RE, ### fix - change to INLINE_NOTE !!!
|
|
122
|
+
DATE_LEGS_RE, # note - must go before date!!!
|
|
123
|
+
DATE_RE, ## note - date must go before time (e.g. 12.12. vs 12.12)
|
|
124
|
+
TIME_RE,
|
|
125
|
+
|
|
126
|
+
ATTENDANCE_RE, # note - allow att: for now inline in matches too - why? why not?
|
|
127
|
+
|
|
128
|
+
SCORE_FULL_1ST_RE, # note - MUST go before SCORE_LEGS_RE!!
|
|
129
|
+
## e.g. 2-2, 5-1 pen.
|
|
130
|
+
SCORE_LEGS_RE,
|
|
131
|
+
SCORE_FULL_RE,
|
|
132
|
+
SCORE_FULLER_RE,
|
|
133
|
+
SCORE_FULLER_MORE_RE,
|
|
134
|
+
SCORE_AWD_RE, # (inline) score awarded e.g. 3-0 awd or 0-1 awd. etc.
|
|
135
|
+
SCORE_ABD_RE, # (inline) score abandoned e.g. 2-1 abd.
|
|
136
|
+
SCORE_RE, ## note basic score e.g. 1-1 must go after SCORE_FULL_RE!!!
|
|
137
|
+
|
|
138
|
+
VS_RE,
|
|
139
|
+
|
|
140
|
+
TEXT_RE,
|
|
141
|
+
|
|
142
|
+
%r{ (?<sym> [,@()-] ) }x, ## todo - check if "standalone" comma (,) in use?
|
|
143
|
+
ANY_RE,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
## ord (for ordinal number)
|
|
152
|
+
## e.g. (51) or (1) etc. - limit digits of number - why? why not???
|
|
153
|
+
|
|
154
|
+
START_WITH_ORD = %r{
|
|
155
|
+
\A
|
|
156
|
+
[ ]* ## ignore leading spaces (if any)
|
|
157
|
+
(?<ord>
|
|
158
|
+
\(
|
|
159
|
+
(?<value>\d+)
|
|
160
|
+
\)
|
|
161
|
+
)}ix
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
###
|
|
165
|
+
## e.g. 1930, 1986, 2002, 2010, 2022, 2026
|
|
166
|
+
## note - only YYYY
|
|
167
|
+
## note - look out for clubs like 1860 München (de) !!!
|
|
168
|
+
## 1899 Hoffenheim (de)
|
|
169
|
+
## 1896 Löwenherz (ch - a.k.a. FC Winterthur ??)
|
|
170
|
+
## any others starting with YYYY ?!
|
|
171
|
+
## note - YEAR requires TWO (trailing) spaces !!!!! e.g.
|
|
172
|
+
## 1930 Uruguay 4-2 Argentina
|
|
173
|
+
## 1934 Italy 2-1 Czechoslovakia (AET)
|
|
174
|
+
## 2022 Argentina 3-3 France (AET, 4-2 pen)
|
|
175
|
+
##
|
|
176
|
+
## do NOT match (iso date!!) - 2020-11-12
|
|
177
|
+
## 2020/11/12
|
|
178
|
+
## 2020.11.12 etc.
|
|
179
|
+
|
|
180
|
+
START_WITH_YEAR = %r{
|
|
181
|
+
\A
|
|
182
|
+
[ ]* ## ignore leading spaces (if any)
|
|
183
|
+
(?<year>
|
|
184
|
+
\d{4}
|
|
185
|
+
)
|
|
186
|
+
## positive lookahead
|
|
187
|
+
(?= [ ]{2} | ## min. TWO spaces!!! or
|
|
188
|
+
[ ]@ | ## space with geo marker or
|
|
189
|
+
[ ]* \z ## year (date) header (end-of-line/string)
|
|
190
|
+
)
|
|
191
|
+
}x
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
###
|
|
196
|
+
## check for headings
|
|
197
|
+
## e.g. = heading 1
|
|
198
|
+
## == heading 2 etc.
|
|
199
|
+
## =Eurochampionship=
|
|
200
|
+
## note - no spaces required (same as in wikipedia!!)
|
|
201
|
+
## same as in wikipedia support six (6) levels
|
|
202
|
+
##
|
|
203
|
+
## note - use \A (instead of ^) - \A strictly matches the start of the string.
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
HEADING_RE = %r{ \A
|
|
207
|
+
[ ]* ## ignore leading spaces (if any)
|
|
208
|
+
(?<heading_marker> ={1,6} )
|
|
209
|
+
[ ]*
|
|
210
|
+
(?<heading>
|
|
211
|
+
## must start with letter - why? why not?
|
|
212
|
+
### 1st round
|
|
213
|
+
## allow numbers e.g. Group A - 1
|
|
214
|
+
[^=]+? ## use non-greedy
|
|
215
|
+
)
|
|
216
|
+
[ ]* ## ignore trailing spaces (if any)
|
|
217
|
+
(?: =*) ## allow any trailing heading markers
|
|
218
|
+
[ ]* ## ignore trailing spaces (if any)
|
|
219
|
+
\z
|
|
220
|
+
}ix
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
end # class Lexer
|
|
224
|
+
end # module Fbtxt
|