1 #Region "Microsoft.VisualBasic::437dfcfa1ae3f76f5dad23333d856db4, Microsoft.VisualBasic.Core\Text\Splitter.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     '     Class Splitter
35     
36     '         Constructor: (+1 OverloadsSub New
37     '         Function: __split, isValidDelimiterBinary, isValidDelimiterText, Split
38     
39     
40     ' /********************************************************************************/
41
42 #End Region
43
44 ' http://www.codeproject.com/Articles/7464/Very-Fast-Splitter-with-support-for-Multi-Characte
45
46 Namespace Text
47
48     ''' <summary>
49     ''' Split strings with support to multi-character, multi-lines Delimiter
50     ''' </summary>
51     Public NotInheritable Class Splitter
52
53         ''' <summary>
54         ''' Holds the string to split
55         ''' </summary>
56         Dim expression As Char()
57         ''' <summary>
58         ''' Delimiter to split the expression with
59         ''' </summary>
60         Dim delimiter As Char()
61
62         ''' <summary>
63         ''' Constrctor for The Splitter
64         ''' </summary>
65         Protected Sub New()
66         End Sub
67
68         Private Function isValidDelimiterBinary(StringIndex As Integer, DelimiterIndex As IntegerAs Boolean
69             If DelimiterIndex = delimiter.Length Then
70                 Return True
71             End If
72             If StringIndex = expression.Length Then
73                 Return False
74             End If
75             If the current character of the expression matches the current character 
76             ' of the Delimiter, then go to next character
77             If expression(StringIndex) = delimiter(DelimiterIndex) Then
78                 Return isValidDelimiterBinary(StringIndex + 1, DelimiterIndex + 1)
79             Else
80                 Return False
81             End If
82         End Function
83
84         Private Function isValidDelimiterText(StringIndex As Integer, DelimiterIndex As IntegerAs Boolean
85             If DelimiterIndex = delimiter.Length Then
86                 Return True
87             End If
88             If StringIndex = expression.Length Then
89                 Return False
90             End If
91             If the current character of the expression matches the current character 
92             ' of the Delimiter, then go to next character
93             If Char.ToLower(expression(StringIndex)) = Char.ToLower(delimiter(DelimiterIndex)) Then
94                 Return isValidDelimiterText(StringIndex + 1, DelimiterIndex + 1)
95             Else
96                 Return False
97             End If
98         End Function
99
100         ''' <summary>
101         ''' 这个是安全的函数,空值会返回空集合
102         ''' </summary>
103         ''' <param name="s"></param>
104         ''' <param name="delimiter"></param>
105         ''' <param name="isSingle"></param>
106         ''' <param name="count"></param>
107         ''' <param name="compare"></param>
108         ''' <returns></returns>
109         Public Shared Function Split(s$, delimiter$, isSingle As Boolean,
110                                      Optional count% = Integer.MaxValue,
111                                      Optional compare As CompareMethod = CompareMethod.Binary) As String()
112             If s.StringEmpty(whitespaceAsEmpty:=False) Then
113                 Return {}
114             Else
115                 Return New Splitter().__split(s, delimiter, isSingle, count, compare)
116             End If
117         End Function
118
119         Private Function __split(expression$, delimiter$, SingleSeparator As Boolean, count%, Compare As CompareMethod) As String()
120             ' Array to hold Splitted Tokens
121             Dim tokens As New List(Of String)
122
123             'Update Private Members
124             Me.expression = expression.ToCharArray
125             Me.delimiter = delimiter.ToCharArray
126
127             'If not using single separator, then use the regular split function
128             If Not SingleSeparator Then
129                 If count >= 0 Then
130                     Return expression.Split(delimiter.ToCharArray(), count)
131                 Else
132                     Return expression.Split(delimiter.ToCharArray())
133                 End If
134             End If
135
136             'Check if count = 0 then return an empty array
137             If count = 0 Then
138                 Return New String(-1) {}
139                 'Check if Count = 1 then return the whole expression
140             ElseIf count = 1 Then
141                 Return New String() {expression}
142             Else
143                 count -= 1
144             End If
145
146             Dim i As Integer
147             Indexer to loop over the string with
148             Dim iStart As Integer = 0
149             'The Start index of the current token in the expression
150             If Compare = CompareMethod.Binary Then
151
152                 For i = 0 To expression.Length - 1
153                     If isValidDelimiterBinary(i, 0) Then
154                         'Assign New Token
155                         tokens.Add(expression.Substring(iStart, i - iStart))
156                         'Update Index
157                         i += delimiter.Length - 1
158                         'Update Current Token Start index
159                         iStart = i + 1
160                         'If we reached the tokens limit , then exit For
161                         If tokens.Count = count AndAlso count >= 0 Then
162                             Exit For
163                         End If
164                     End If
165                 Next
166             Else
167                 For i = 0 To expression.Length - 1
168                     If isValidDelimiterText(i, 0) Then
169                         'Assign New Token
170                         tokens.Add(expression.Substring(iStart, i - iStart))
171                         'Update Index
172                         i += delimiter.Length - 1
173                         'Update Current Token Start index
174                         iStart = i + 1
175                         'If we reached the tokens limit , then exit For
176                         If tokens.Count = count AndAlso count >= 0 Then
177                             Exit For
178                         End If
179                     End If
180                 Next
181             End If
182             Dim LastToken As String = ""
183             'If there is still data & have not been added
184             If iStart < expression.Length Then
185                 LastToken = expression.Substring(iStart, expression.Length - iStart)
186                 If LastToken = delimiter Then
187                     tokens.Add(Nothing)
188                 Else
189                     tokens.Add(LastToken)
190                 End If
191                 'If there is no elements in the tokens array , then pass the whole string as the one element
192             ElseIf tokens.Count = 0 Then
193                 tokens.Add(expression)
194             End If
195
196             'Return Splitted Tokens
197             Return tokens.ToArray
198         End Function
199     End Class
200 End Namespace