1 #Region "Microsoft.VisualBasic::3e2e47467413833e6181b7ac1c226ab6, Microsoft.VisualBasic.Core\Text\Patterns\Wildcards.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     '     Module WildcardsExtension
35     
36     '         Function: (+2 Overloads) WildcardMatch
37     
38     
39     ' /********************************************************************************/
40
41 #End Region
42
43 Imports System.Runtime.CompilerServices
44
45 Namespace Text.Patterns
46
47     ''' <summary>
48     ''' Extensions to <see cref="String"/> by using wildcards to match string
49     ''' 
50     ''' ###### A very simple wildcard match
51     ''' > https://github.com/picrap/WildcardMatch
52     ''' </summary>
53     Public Module WildcardsExtension
54
55         ''' <summary>
56         ''' Tells if the given string matches the given wildcard.
57         ''' Two wildcards are allowed: ``*`` and ``%``.
58         ''' 
59         ''' + '*' matches any ZERO or more characters
60         ''' + '%' matches any single character
61         ''' </summary>
62         ''' <param name="wildcard">The wildcard.</param>
63         ''' <param name="s">The s.</param>
64         ''' <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
65         ''' <returns></returns>
66         ''' 
67         <MethodImpl(MethodImplOptions.AggressiveInlining)>
68         <Extension>
69         Public Function WildcardMatch(wildcard$, s$, Optional ignoreCase As Boolean = FalseAs Boolean
70             Return WildcardMatch(wildcard, s, 0, 0, ignoreCase)
71         End Function
72
73         Const NeverRun$ = "This code is never run, so this exception is useless."
74
75         ''' <summary>
76         ''' Internal matching algorithm.
77         ''' </summary>
78         ''' <param name="wildcard">The wildcard.</param>
79         ''' <param name="s">The s.</param>
80         ''' <param name="wildcardIndex">Index of the wildcard.</param>
81         ''' <param name="sIndex">Index of the s.</param>
82         ''' <param name="ignoreCase">if set to <c>true</c> [ignore case].</param>
83         ''' <returns></returns>
84         <Extension>
85         Private Function WildcardMatch(wildcard$, s$, wildcardIndex%, sIndex%, ignoreCase As BooleanAs Boolean
86             Do While True
87                 ' in the wildcard end, if we are at tested string end, then strings match
88                 If wildcardIndex = wildcard.Length Then
89                     Return sIndex = s.Length
90                 End If
91
92                 Dim c As Char = wildcard(wildcardIndex)
93
94                 Select Case c
95
96                 ' always a match
97                     Case "%"c
98                     Case "*"c
99
100                         ' if this is the last wildcard char, then we have a match, whatever the tested string is
101                         If wildcardIndex = wildcard.Length - 1 Then
102                             Return True
103                         End If
104
105                         ' test if a match follows
106                         Return Enumerable _
107                             .Range(sIndex, s.Length - 1) _
108                             .Any(Function(i)
109                                      Return WildcardMatch(wildcard, s, wildcardIndex + 1, i, ignoreCase)
110                                  End Function)
111                     Case Else
112                         If sIndex < s.Length Then
113                             Dim cc = If(ignoreCase, Char.ToLower(c), c)
114                             Dim sc = If(ignoreCase, Char.ToLower(s(sIndex)), s(sIndex))
115
116                             If cc <> sc Then
117                                 Return False
118                             End If
119                         End If
120                 End Select
121
122                 wildcardIndex += 1
123                 sIndex += 1
124             Loop
125
126             ' disable the warning for function no returns value.
127             Throw New Exception(NeverRun)
128         End Function
129     End Module
130 End Namespace