1 |
#Region "Microsoft.VisualBasic::4680cb3e575391539fa5ed5c351c78c7, Microsoft.VisualBasic.Core\Scripting\TextGrepScriptEngine.vb"
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
#End Region
|
56 |
|
57 |
Imports System.Runtime.CompilerServices
|
58 |
Imports System.Text
|
59 |
Imports System.Text.RegularExpressions
|
60 |
Imports Microsoft.VisualBasic.CommandLine
|
61 |
Imports Microsoft.VisualBasic.CommandLine.Reflection
|
62 |
Imports Microsoft.VisualBasic.Language
|
63 |
Imports Microsoft.VisualBasic.Language.Default
|
64 |
Imports Token = System.Collections.Generic.KeyValuePair(Of String(), Microsoft.VisualBasic.Scripting.TextGrepMethodToken)
|
65 |
Imports r = System.Text.RegularExpressions.Regex
|
66 |
Imports System.ComponentModel
|
67 |
|
68 |
Namespace Scripting
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
Public Delegate Function TextGrepMethodToken(source$, args$()) As String
|
78 |
Public Delegate Function TextGrepMethod(source As String) As String
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
Public NotInheritable Class TextGrepScriptEngine
|
86 |
|
87 |
Public Shared ReadOnly Property MethodPointers As New SortedDictionary(Of String, TextGrepMethodToken) From {
|
88 |
_
|
89 |
{"tokens", AddressOf TextGrepScriptEngine.Tokens},
|
90 |
{"match", AddressOf TextGrepScriptEngine.Match},
|
91 |
{"-", AddressOf TextGrepScriptEngine.NoOperation},
|
92 |
{"replace", AddressOf TextGrepScriptEngine.Replace},
|
93 |
{"mid", AddressOf TextGrepScriptEngine.MidString},
|
94 |
{"reverse", AddressOf TextGrepScriptEngine.Reverse}
|
95 |
}
|
96 |
|
97 |
Public Shared Function EnsureNotEmpty(ptr As TextGrepMethod) As TextGrepMethod
|
98 |
Return Function(str) As String
|
99 |
Dim gs$ = ptr(str)
|
100 |
|
101 |
If gs.StringEmpty Then
|
102 |
Return str
|
103 |
Else
|
104 |
Return gs
|
105 |
End If
|
106 |
End Function
|
107 |
End Function
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
Dim _operations As Token()
|
114 |
Dim _script$()
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
Public ReadOnly Property IsDoNothing As Boolean
|
121 |
Get
|
122 |
Dim emptyScript = _script.IsNullOrEmpty
|
123 |
Dim emptyOperation = _script.Length = 1 AndAlso (_script.First = "-" OrElse _script.First.StringEmpty)
|
124 |
|
125 |
Return emptyScript OrElse emptyOperation
|
126 |
End Get
|
127 |
End Property
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
<ExportAPI("compile", Info:="", Usage:="script_tokens1;script_tokens2;....", Example:="")>
|
138 |
Public Shared Function Compile(scriptText As String) As TextGrepScriptEngine
|
139 |
If scriptText.StringEmpty Then
|
140 |
Return DoNothing
|
141 |
ElseIf scriptText = "-" Then
|
142 |
Return DoNothing
|
143 |
Else
|
144 |
Return CompileInternal(scriptText)
|
145 |
End If
|
146 |
End Function
|
147 |
|
148 |
Private Shared Function CompileInternal(scriptText As String) As TextGrepScriptEngine
|
149 |
Dim script$() = TryParse(scriptText, TokenDelimited:=";", InnerDelimited:="'"c)
|
150 |
Dim builder = LinqAPI.Exec(Of Token) <=
|
151 |
_
|
152 |
From sToken As String
|
153 |
In script
|
154 |
Let tokens As String() = TryParse(sToken, TokenDelimited:=" ", InnerDelimited:="'"c)
|
155 |
Let entryPoint As String = sToken.Split.First.ToLower
|
156 |
Where MethodPointers.ContainsKey(entryPoint)
|
157 |
Select New Token(tokens, _MethodPointers(entryPoint))
|
158 |
|
159 |
If script.Length > builder.Length Then
|
160 |
|
161 |
|
162 |
|
163 |
Return Nothing
|
164 |
Else
|
165 |
Return New TextGrepScriptEngine With {
|
166 |
._script = script,
|
167 |
._operations = builder
|
168 |
}
|
169 |
End If
|
170 |
End Function
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
Public Shared ReadOnly Property DoNothing As DefaultValue(Of TextGrepScriptEngine)
|
177 |
Get
|
178 |
Static opNothing As New TextGrepScriptEngine With {
|
179 |
._operations = {},
|
180 |
._script = {"-"}
|
181 |
}
|
182 |
Return opNothing
|
183 |
End Get
|
184 |
End Property
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
Public ReadOnly Property PipelinePointer As TextGrepMethod
|
192 |
<MethodImpl(MethodImplOptions.AggressiveInlining)>
|
193 |
Get
|
194 |
Return AddressOf Grep
|
195 |
End Get
|
196 |
End Property
|
197 |
|
198 |
Public Iterator Function Explains() As IEnumerable(Of String)
|
199 |
For Each op As Token In _operations
|
200 |
Dim args$() = op.Key.Skip(1).Join("*".Replicate(5)).ToArray
|
201 |
Dim description As DescriptionAttribute = op.Value _
|
202 |
.Method _
|
203 |
.GetCustomAttributes(GetType(DescriptionAttribute), True) _
|
204 |
.First
|
205 |
Dim explain$ = String.Format(description.Description, args)
|
206 |
|
207 |
Yield explain
|
208 |
Next
|
209 |
End Function
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
Public Function Grep(source As String) As String
|
218 |
Dim doGrep As Func(Of String, Token, Integer) =
|
219 |
Function(sourceText As String, method As Token) As Integer
|
220 |
source = method.Value()(sourceText, method.Key)
|
221 |
Return Len(source)
|
222 |
End Function
|
223 |
|
224 |
|
225 |
For Each operation As Token In _operations
|
226 |
Call doGrep(source, operation)
|
227 |
Next
|
228 |
|
229 |
Return source
|
230 |
End Function
|
231 |
|
232 |
<MethodImpl(MethodImplOptions.AggressiveInlining)>
|
233 |
Public Overrides Function ToString() As String
|
234 |
Return _script.JoinBy(" -> ")
|
235 |
End Function
|
236 |
|
237 |
Protected Friend Sub New()
|
238 |
End Sub
|
239 |
|
240 |
#Region "API supports"
|
241 |
|
242 |
<MethodImpl(MethodImplOptions.AggressiveInlining)>
|
243 |
<ExportAPI("-", Info:="DO_NOTHING")>
|
244 |
<Description("Do nothing with the source input")>
|
245 |
Private Shared Function NoOperation(source As String, script As String()) As String
|
246 |
Return source
|
247 |
End Function
|
248 |
|
249 |
<MethodImpl(MethodImplOptions.AggressiveInlining)>
|
250 |
<ExportAPI("Reverse")>
|
251 |
<Description("Reverse the input source text")>
|
252 |
Private Shared Function Reverse(source As String, Script As String()) As String
|
253 |
Return source.Reverse.ToArray
|
254 |
End Function
|
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 |
<ExportAPI("Tokens", Info:="", Usage:="tokens p_str pointer", Example:="")>
|
264 |
<Argument("pointer", False, Description:="pointer must be a zero base integer number which is smaller than
|
265 |
the tokens array's length; pointer can also be assign of a specific string ""last"" to get the last
|
266 |
element and ""first"" to get the first element in the tokens array.")>
|
267 |
<Description("Split source text with delimiter [{0}], and get the token at position [{1}]")>
|
268 |
Private Shared Function Tokens(source As String, script As String()) As String
|
269 |
Dim delimiter As String = script(1)
|
270 |
Dim Tstr As String() = Strings.Split(source, delimiter)
|
271 |
|
272 |
If String.Equals(script(2), "last", StringComparison.OrdinalIgnoreCase) Then
|
273 |
Return If(Tstr.IsNullOrEmpty, "", Tstr.Last)
|
274 |
Else
|
275 |
|
276 |
Dim p As Integer = CInt(Val(script(2)))
|
277 |
|
278 |
If Tstr.Length - 1 < p OrElse p < 0 Then
|
279 |
Return ""
|
280 |
Else
|
281 |
Return If(Tstr.IsNullOrEmpty, "", Tstr(p))
|
282 |
End If
|
283 |
End If
|
284 |
End Function
|
285 |
|
286 |
<ExportAPI("match", Info:="", Usage:="match pattern", Example:="")>
|
287 |
<Description("Get the text token which match pattern [{0}]")>
|
288 |
Private Shared Function Match(source As String, script As String()) As String
|
289 |
Dim pattern As String = script.Last
|
290 |
Return r.Match(source, pattern, RegexOptions.IgnoreCase).Value
|
291 |
End Function
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 |
<ExportAPI("mid", Info:="Substring a token from the input text source.")>
|
303 |
<Description("Substring a region [{0}, {1}] from the input text source.")>
|
304 |
Private Shared Function MidString(source As String, script As String()) As String
|
305 |
Dim start As Integer = CInt(Val(script(1)))
|
306 |
|
307 |
If script.Length > 2 Then
|
308 |
Dim length As Integer = CInt(Val(script(2)))
|
309 |
Return Mid(source, start, length)
|
310 |
Else
|
311 |
Return Mid(source, start)
|
312 |
End If
|
313 |
End Function
|
314 |
|
315 |
<ExportAPI("replace", Usage:="replace <regx_text> <replace_value>")>
|
316 |
<Description("replace source with [{1}] where match pattern [{0}]")>
|
317 |
Private Shared Function Replace(source As String, script As String()) As String
|
318 |
Dim regexp As New Regex(script(1))
|
319 |
Dim matchs = regexp.Matches(source)
|
320 |
Dim sBuilder As New StringBuilder(source)
|
321 |
Dim newValue = script(2)
|
322 |
|
323 |
For Each m As Match In matchs
|
324 |
Call sBuilder.Replace(m.Value, newValue)
|
325 |
Next
|
326 |
|
327 |
Return sBuilder.ToString
|
328 |
End Function
|
329 |
#End Region
|
330 |
End Class
|
331 |
End Namespace
|