| 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 |