1 | #Region "Microsoft.VisualBasic::7aa365d9fe12cfeb3d5af60dae796238, Microsoft.VisualBasic.Core\Scripting\Expressions\StringInterpolation.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 StringInterpolation |
35 | ' |
36 | ' Function: GetValue, (+2 Overloads) Interpolate |
37 | ' |
38 | ' Sub: Interpolate |
39 | ' |
40 | ' |
41 | ' /********************************************************************************/ |
42 | |
43 | #End Region |
44 | |
45 | Imports System.Runtime.CompilerServices |
46 | Imports System.Text |
47 | Imports System.Text.RegularExpressions |
48 | Imports VBCodePatterns = Microsoft.VisualBasic.Scripting.SymbolBuilder.VBLanguage.Patterns |
49 | |
50 | Namespace Scripting.Expressions |
51 | |
52 | ''' <summary> |
53 | ''' 简单的字符串插值引擎,可以用来调试字符串表达式的处理结果 |
54 | ''' </summary> |
55 | Public Module StringInterpolation |
56 | |
57 | ' "abcdefg$h$i is $k \$a" |
58 | |
59 | Const VB_str$ = "&VB_str" |
60 | |
61 | ''' <summary> |
62 | ''' 允许下换线,点号,ASCII字母,以及数字作为标识符 |
63 | ''' |
64 | ''' ``` |
65 | ''' $var |
66 | ''' $obj.property |
67 | ''' $obj.property.value.method.etc |
68 | ''' ``` |
69 | ''' </summary> |
70 | Const VariablePattern$ = "[$]" & VBCodePatterns.Identifer & "(\." & VBCodePatterns.Identifer & ")*" |
71 | |
72 | ''' <summary> |
73 | ''' 不存在的键名会自动返回空字符串 |
74 | ''' </summary> |
75 | ''' <param name="resource"></param> |
76 | ''' <returns></returns> |
77 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
78 | <Extension> |
79 | Public Function GetValue(resource As Dictionary(Of String, String)) As Func(Of String, String) |
80 | Return Function(name$) |
81 | If resource.ContainsKey(name) Then |
82 | Return resource(name$) |
83 | Else |
84 | Return Nothing |
85 | End If |
86 | End Function |
87 | End Function |
88 | |
89 | ''' <summary> |
90 | ''' 对于<paramref name="getValue"/>方法而言,是不需要``$``前缀了的 |
91 | ''' </summary> |
92 | ''' <param name="expr$"> |
93 | ''' 只有当变量的值不为空值的时候才会进行替换,但是当<paramref name="nullAsEmpty"/>为真的时候会被强行替换为空字符串进行替换 |
94 | ''' </param> |
95 | ''' <param name="getValue">Get string value of the variable in the expression.</param> |
96 | ''' <param name="escape"> |
97 | ''' 是否需要进行对\t\n这类字符的转义操作?假若是路径字符串,则不推荐开启这个选项了,因为路径的分隔符很容易引起误转义... |
98 | ''' </param> |
99 | ''' <returns></returns> |
100 | <Extension> |
101 | Public Function Interpolate(expr$, getValue As Func(Of String, String), |
102 | Optional nullAsEmpty As Boolean = False, |
103 | Optional escape As Boolean = True) As String |
104 | |
105 | With New StringBuilder(expr) |
106 | Call .Interpolate(getValue, nullAsEmpty, escape) |
107 | Return .ToString |
108 | End With |
109 | End Function |
110 | |
111 | ''' <summary> |
112 | ''' 在解析出variable之后,variable前面的``$``是会被清除掉的,所以variable的source <paramref name="getValue"/>里面的变量名称应该是没有``$``前缀的 |
113 | ''' </summary> |
114 | ''' <param name="sb"></param> |
115 | ''' <param name="getValue"></param> |
116 | ''' <param name="nullAsEmpty">只有当变量的值不为空值的时候才会进行替换,但是当<paramref name="nullAsEmpty"/>为真的时候会被强行替换为空字符串进行替换</param> |
117 | ''' <param name="escape"></param> |
118 | <Extension> |
119 | Public Sub Interpolate(ByRef sb As StringBuilder, getValue As Func(Of String, String), |
120 | Optional nullAsEmpty As Boolean = False, |
121 | Optional escape As Boolean = True) |
122 | |
123 | Call sb.Replace("\$", VB_str) |
124 | |
125 | For Each v$ In Regex _ |
126 | .Matches(sb.ToString, VariablePattern, RegexICSng) _ |
127 | .ToArray _ |
128 | .OrderByDescending(Function(s) s.Length) _ |
129 | .ToArray |
130 | |
131 | Dim value$ = getValue(Mid(v, 2)) |
132 | |
133 | If value Is Nothing AndAlso nullAsEmpty Then |
134 | value = "" |
135 | End If |
136 | |
137 | ' 只对非空值进行替换 |
138 | If Not value Is Nothing Then |
139 | Call sb.Replace(v, value) |
140 | End If |
141 | Next |
142 | |
143 | With sb |
144 | ' 这个必须要转义 |
145 | .Replace(VB_str, "$") |
146 | |
147 | ' 根据需要来进行转义,对于Windows文件路径而言,不推荐转义 |
148 | ' 因为Windows的文件路径分隔符为\,很容易引起误解,例如C:\tsv会被误转义为C:<TAB>sv而导致错误 |
149 | If escape Then |
150 | Call .Replace("\n", vbLf) |
151 | Call .Replace("\t", vbTab) |
152 | End If |
153 | End With |
154 | End Sub |
155 | |
156 | <MethodImpl(MethodImplOptions.AggressiveInlining)> |
157 | <Extension> |
158 | Public Function Interpolate(expr$, table As Dictionary(Of String, String), Optional nullAsEmpty As Boolean = False) As String |
159 | Return expr.Interpolate(table.GetValue, nullAsEmpty) |
160 | End Function |
161 | End Module |
162 | End Namespace |