@@ -80,6 +80,12 @@ extension Terminator: ExpressibleByStringLiteral {
80
80
/// which gets all substrings that appear between a set of
81
81
/// identifiers and terminators passed to its handler.
82
82
public struct Matcher {
83
+ /// Closure type used to define a handler for a matcher. When
84
+ /// a match is found, the handler is passed the substring that
85
+ /// was matched, as well as the range containing the match plus
86
+ /// the identifier and terminator that the match is located between.
87
+ public typealias Handler = ( Substring , ClosedRange < String . Index > ) -> Void
88
+
83
89
/// The identifiers to look for when scanning. When any
84
90
/// of the identifiers are found, a matching session begins.
85
91
public var identifiers : [ Identifier ]
@@ -91,13 +97,13 @@ public struct Matcher {
91
97
/// The handler to be called when a match was found. A match
92
98
/// is considered found when a substring appears between any
93
99
/// of the matcher's identifiers and its terminators.
94
- public var handler : ( Substring ) -> Void
100
+ public var handler : Handler
95
101
96
102
/// Create a new matcher with the desired parameters. See
97
103
/// the documentation for each property for more information.
98
104
public init ( identifiers: [ Identifier ] ,
99
105
terminators: [ Terminator ] ,
100
- handler: @escaping ( Substring ) -> Void ) {
106
+ handler: @escaping Handler ) {
101
107
self . identifiers = identifiers
102
108
self . terminators = terminators
103
109
self . handler = handler
@@ -109,7 +115,7 @@ public extension Matcher {
109
115
/// identifier and terminator, rather than arrays of them.
110
116
init ( identifier: Identifier ,
111
117
terminator: Terminator ,
112
- handler: @escaping ( Substring ) -> Void ) {
118
+ handler: @escaping Handler ) {
113
119
self . init ( identifiers: [ identifier] ,
114
120
terminators: [ terminator] ,
115
121
handler: handler)
@@ -134,7 +140,9 @@ public extension StringProtocol where SubSequence == Substring {
134
140
scan ( using: [ Matcher (
135
141
identifiers: identifiers,
136
142
terminators: terminators,
137
- handler: { matches. append ( $0) }
143
+ handler: { match, _ in
144
+ matches. append ( match)
145
+ }
138
146
) ] )
139
147
140
148
return matches
@@ -143,16 +151,13 @@ public extension StringProtocol where SubSequence == Substring {
143
151
/// Scan this string using a custom array of matchers, defined using
144
152
/// the `Matcher` type, which gets to handle all matched substrings.
145
153
func scan( using matchers: [ Matcher ] ) {
146
- typealias Session = ( matcher: Matcher , range: ClosedRange < Index > )
147
-
148
- var activeSessions = [ Session] ( )
149
- var partialSessions = [ Session] ( )
154
+ var activeSessions = [ ( Matcher , Identifier , ClosedRange < Index > ) ] ( )
155
+ var partialSessions = [ ( Matcher , ClosedRange < Index > ) ] ( )
150
156
var idleMatchers = matchers
151
157
152
158
for index in indices {
153
- activeSessions = activeSessions. compactMap {
154
- let matcher = $0. matcher
155
- let range = $0. range. lowerBound... index
159
+ activeSessions = activeSessions. compactMap { matcher, identifier, range in
160
+ let range = range. lowerBound... index
156
161
let match = self [ range]
157
162
158
163
for terminator in matcher. terminators {
@@ -170,20 +175,21 @@ public extension StringProtocol where SubSequence == Substring {
170
175
offsetBy: - terminator. string. count)
171
176
172
177
if endIndex >= range. lowerBound {
173
- let range = range. lowerBound... endIndex
174
- matcher. handler ( self [ range] )
178
+ let match = self [ range. lowerBound... endIndex]
179
+ let identifierLength = identifier. string. count
180
+ let lowerBound = self . index ( range. lowerBound, offsetBy: - identifierLength)
181
+ matcher. handler ( match, lowerBound... range. upperBound)
175
182
}
176
183
177
184
idleMatchers. append ( matcher)
178
185
return nil
179
186
}
180
187
181
- return ( matcher, range)
188
+ return ( matcher, identifier , range)
182
189
}
183
190
184
- partialSessions = partialSessions. compactMap {
185
- let matcher = $0. matcher
186
- let range = $0. range. lowerBound... index
191
+ partialSessions = partialSessions. compactMap { matcher, range in
192
+ let range = range. lowerBound... index
187
193
let match = self [ range]
188
194
189
195
for identifier in matcher. identifiers {
@@ -197,7 +203,7 @@ public extension StringProtocol where SubSequence == Substring {
197
203
198
204
let nextIndex = self . index ( after: index)
199
205
let range = nextIndex... nextIndex
200
- activeSessions. append ( ( matcher, range) )
206
+ activeSessions. append ( ( matcher, identifier , range) )
201
207
return nil
202
208
}
203
209
@@ -216,7 +222,8 @@ public extension StringProtocol where SubSequence == Substring {
216
222
if identifier. string. first == self [ index] {
217
223
if identifier. string. count == 1 {
218
224
let nextIndex = self . index ( after: index)
219
- activeSessions. append ( ( matcher, nextIndex... nextIndex) )
225
+ let range = nextIndex... nextIndex
226
+ activeSessions. append ( ( matcher, identifier, range) )
220
227
} else {
221
228
partialSessions. append ( ( matcher, index... index) )
222
229
}
0 commit comments