1 #Region "Microsoft.VisualBasic::94bfff43ee84da6d1d62557ab3b1ea2e, Microsoft.VisualBasic.Core\Scripting\TextGrepScriptEngine.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Delegate Function
35     
36     
37     '     Delegate Function
38     
39     
40     '     Class TextGrepScriptEngine
41     
42     '         Properties: MethodPointers, PipelinePointer
43     
44     '         Constructor: (+1 OverloadsSub New
45     '         Function: Compile, Grep, Match, MidString, NoOperation
46     '                   Replace, Reverse, Tokens, ToString
47     
48     
49     
50     
51     
52     ' /********************************************************************************/
53
54 #End Region
55
56 Imports System.Runtime.CompilerServices
57 Imports System.Text
58 Imports System.Text.RegularExpressions
59 Imports Microsoft.VisualBasic.CommandLine
60 Imports Microsoft.VisualBasic.CommandLine.Reflection
61 Imports Microsoft.VisualBasic.Language
62 Imports Token = System.Collections.Generic.KeyValuePair(Of String(), Microsoft.VisualBasic.Scripting.TextGrepMethodToken)
63
64 Namespace Scripting
65
66     ''' <summary>
67     ''' 
68     ''' </summary>
69     ''' <param name="source">文本源</param>
70     ''' <param name="args">脚本命令的参数</param>
71     ''' <returns></returns>
72     ''' <remarks></remarks>
73     Public Delegate Function TextGrepMethodToken(source$, args$()) As String
74     Public Delegate Function TextGrepMethod(source As StringAs String
75
76     ''' <summary>
77     ''' A script object for grep the gene id in the blast output query and subject title.
78     ''' (用于解析基因名称的脚本类,这个对象是在项目的初始阶段,为了方便命令行操作而设置的)
79     ''' </summary>
80     ''' <remarks></remarks>
81     Public NotInheritable Class TextGrepScriptEngine
82
83         Public Shared ReadOnly Property MethodPointers As New SortedDictionary(Of String, TextGrepMethodToken) From {
84  _
85             {"tokens"AddressOf TextGrepScriptEngine.Tokens},
86             {"match"AddressOf TextGrepScriptEngine.Match},
87             {"-"AddressOf TextGrepScriptEngine.NoOperation},
88             {"replace"AddressOf TextGrepScriptEngine.Replace},
89             {"mid"AddressOf TextGrepScriptEngine.MidString},
90             {"reverse"AddressOf TextGrepScriptEngine.Reverse}
91         }
92
93         Public Shared Function EnsureNotEmpty(ptr As TextGrepMethod) As TextGrepMethod
94             Return Function(str) As String
95                        Dim gs$ = ptr(str)
96
97                        If gs.StringEmpty Then
98                            Return str
99                        Else
100                            Return gs
101                        End If
102                    End Function
103         End Function
104
105         ''' <summary>
106         ''' Source,Script,ReturnValue
107         ''' </summary>
108         ''' <remarks></remarks>
109         Dim _operations As Token()
110         Dim _script$
111
112         ''' <summary>
113         ''' 对用户所输入的脚本进行编译,对于内部的空格,请使用单引号``'``进行分割
114         ''' </summary>
115         ''' <returns></returns>
116         ''' <remarks></remarks>
117         <ExportAPI("compile"Info:="", Usage:="script_tokens1;script_tokens2;....", Example:="")>
118         Public Shared Function Compile(scriptText As StringAs TextGrepScriptEngine
119             Dim Script As String() = TryParse(scriptText, TokenDelimited:=";"InnerDelimited:="'"c)
120             Dim builder = LinqAPI.Exec(Of Token) <=
121  _
122                 From sToken As String
123                 In Script
124                 Let tokens As String() = TryParse(sToken, TokenDelimited:=" "InnerDelimited:="'"c)
125                 Let EntryPoint As String = sToken.Split.First.ToLower
126                 Where MethodPointers.ContainsKey(EntryPoint)
127                 Select New Token(tokens, _MethodPointers(EntryPoint))
128
129             If Script.Length > builder.Length Then
130                 ' 有非法的命令短语,则为了保护数据的一致性,这个
131                 ' 含有错误的语法的脚本是不能够用于操作的, 
132                 ' 则函数返回空指针
133                 Return Nothing
134             Else
135                 Return New TextGrepScriptEngine With {
136                     ._script = scriptText,
137                     ._operations = builder
138                 }
139             End If
140         End Function
141
142         ''' <summary>
143         ''' <see cref="Grep"/>
144         ''' 字符串剪裁操作的函数指针
145         ''' </summary>
146         ''' <returns></returns>
147         Public ReadOnly Property PipelinePointer As TextGrepMethod
148             <MethodImpl(MethodImplOptions.AggressiveInlining)>
149             Get
150                 Return AddressOf Me.Grep
151             End Get
152         End Property
153
154         ''' <summary>
155         ''' 修整目标字符串,按照脚本之中的方法取出所需要的字符串信息
156         ''' </summary>
157         ''' <param name="source"></param>
158         ''' <returns></returns>
159         ''' <remarks></remarks>
160         Public Function Grep(source As StringAs String
161             Dim __parser As Func(Of StringToken, Integer) =
162                 Function(sourceText As String, method As Token) As Integer
163                     source = method.Value()(sourceText, method.Key) '迭代解析
164                     Return Len(source)
165                 End Function
166
167             ' 这里是迭代计算,所以请不要使用并行拓展
168             For Each operation As Token In _operations
169                 Call __parser(source, operation)
170             Next
171
172             Return source
173         End Function
174
175         <MethodImpl(MethodImplOptions.AggressiveInlining)>
176         Public Overrides Function ToString() As String
177             Return _script
178         End Function
179
180         Protected Friend Sub New()
181         End Sub
182
183         <MethodImpl(MethodImplOptions.AggressiveInlining)>
184         <ExportAPI("-"Info:="DO_NOTHING")>
185         Private Shared Function NoOperation(source As String, script As String()) As String
186             Return source
187         End Function
188
189         <MethodImpl(MethodImplOptions.AggressiveInlining)>
190         <ExportAPI("Reverse")>
191         Private Shared Function Reverse(source As String, Script As String()) As String
192             Return source.Reverse.ToArray
193         End Function
194
195         ''' <summary>
196         ''' 
197         ''' </summary>
198         ''' <param name="Source"></param>
199         ''' <param name="Script"></param>
200         ''' <returns></returns>
201         ''' <remarks></remarks>
202         <ExportAPI("Tokens"Info:="", Usage:="tokens p_str pointer", Example:="")>
203         <Argument("pointer"False,
204                   Description:="pointer must be a zero base integer number which is smaller than the tokens array's length; pointer can also be assign of a specific string ""last"" to get the last element and ""first"" to get the first element in the tokens array.")>
205         Private Shared Function Tokens(source As String, script As String()) As String
206             Dim Delimiter As String = script(1)
207             Dim Tstr As String() = Strings.Split(source, Delimiter)
208
209             If String.Equals(script(2), "last"StringComparison.OrdinalIgnoreCase) Then
210                 Return If(Tstr.IsNullOrEmpty, "", Tstr.Last)
211             Else
212                 Dim p As Integer = CInt(Val(script(2))) ' first指示符被计算为0,所以在这里不需要为first进行额外的处理
213
214                 If Tstr.Length - 1 < p OrElse p < 0 Then
215                     Return ""
216                 Else
217                     Return If(Tstr.IsNullOrEmpty, "", Tstr(p))
218                 End If
219             End If
220         End Function
221
222         <ExportAPI("match"Info:="", Usage:="match pattern", Example:="")>
223         Private Shared Function Match(source As String, script As String()) As String
224             Dim pattern As String = script.Last
225             Return Regex.Match(source, pattern).Value
226         End Function
227
228         ''' <summary>
229         ''' 
230         ''' </summary>
231         ''' <param name="source"></param>
232         ''' <param name="ScriptTokens">向量之中的第一个元素为命令的名字,第二个元素为Mid函数的Start参数,第三个元素为Mid函数的Length参数,可以被忽略掉</param>
233         ''' <returns></returns>
234         ''' <remarks></remarks>
235         <ExportAPI("mid"Info:="Substring a token from the input text source.")>
236         Private Shared Function MidString(Source As String, ScriptTokens As String()) As String
237             Dim Start As Integer = CInt(Val(ScriptTokens(1)))
238
239             If ScriptTokens.Length > 2 Then
240                 Dim Length As Integer = CInt(Val(ScriptTokens(2)))
241                 Return Mid(Source, Start, Length)
242             Else
243                 Return Mid(Source, Start)
244             End If
245         End Function
246
247         <ExportAPI("replace", Usage:="replace <regx_text> <replace_value>")>
248         Private Shared Function Replace(source As String, script As String()) As String
249             Dim Regx As New Regex(script(1))
250             Dim Matchs = Regx.Matches(source)
251             Dim sBuilder As New StringBuilder(source)
252             Dim NewValue = script(2)
253
254             For Each m As Match In Matchs
255                 Call sBuilder.Replace(m.Value, NewValue)
256             Next
257
258             Return sBuilder.ToString
259         End Function
260     End Class
261 End Namespace