1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Text ;
4
+ using System . Text . RegularExpressions ;
5
+ using System . Web . UI ;
6
+
7
+ namespace BorderlessGaming . Extensions
8
+ {
9
+ /// <summary>
10
+ /// Enum FormatTokenFlags
11
+ /// </summary>
12
+ public enum FormatTokenFlags
13
+ {
14
+ /// <summary>
15
+ /// Uses the specifier token as the replacement token, matches '%' but not '%%'
16
+ /// </summary>
17
+ SpecifierToken ,
18
+
19
+ /// <summary>
20
+ /// Like String.Format
21
+ /// </summary>
22
+ IndexToken ,
23
+
24
+ /// <summary>
25
+ /// Extracts an Object's Members by name.
26
+ /// </summary>
27
+ MemberToken
28
+ }
29
+
30
+ /// <summary>
31
+ /// Class StringExtensions
32
+ /// </summary>
33
+ public static class StringExtensions
34
+ {
35
+ /// <summary>
36
+ /// The Reformatting function called to format the string with a list of arguments.
37
+ /// </summary>
38
+ private static Func < Func < string , object > , string , IList < object > , string > _regexReformatter ;
39
+
40
+ /// <summary>
41
+ /// The Regex which matches the specifier token in strings.
42
+ /// </summary>
43
+ private static Regex _specifierTokenRegex ;
44
+
45
+ /// <summary>
46
+ /// The Regex which matches parameter indexes in strings, same as string.Format.
47
+ /// </summary>
48
+ private static Regex _argumentIndexRegex ;
49
+
50
+ /// <summary>
51
+ /// The Regex which matches object member names in strings.
52
+ /// </summary>
53
+ private static Regex _objectMemberRegex ;
54
+
55
+ /// <summary>
56
+ /// Splits a string into an array of strings, the string is split by commas.
57
+ /// </summary>
58
+ /// <param name="this">The string instance to split by commas.</param>
59
+ /// <returns>The <paramref name="this" /> string that has been comma separated into substrings.</returns>
60
+ public static string [ ] CommaSeparate ( this string @this )
61
+ {
62
+ return @this . Split ( "," . ToCharArray ( ) , StringSplitOptions . RemoveEmptyEntries ) ;
63
+ }
64
+
65
+ /// <summary>
66
+ /// Determines whether two String objects contain the same data, ignoring the case of the letters in the String; uses
67
+ /// Ordinal comparison.
68
+ /// </summary>
69
+ /// <param name="this">The current string to be compared to.</param>
70
+ /// <param name="other">The other string to compare against the current String for equality.</param>
71
+ /// <returns><c>true</c> if the two strings are equal, <c>false</c> otherwise</returns>
72
+ public static bool EqualsIgnoreCase ( this string @this , string other )
73
+ {
74
+ return string . Equals ( @this , other , StringComparison . OrdinalIgnoreCase ) ;
75
+ }
76
+
77
+ /// <summary>
78
+ /// Replaces one or more format items in a specified string with the string representation of a specified object.
79
+ /// </summary>
80
+ /// <returns>
81
+ /// A copy of <paramref name="format" /> in which any format items are replaced by the string representation of
82
+ /// <paramref name="values" />.
83
+ /// </returns>
84
+ /// <param name="format">A composite format string. </param>
85
+ /// <param name="values">The arguments to use in formatting <paramref name="format" />.</param>
86
+ public static string Form ( this string format , params object [ ] values )
87
+ {
88
+ var specifierTokenMatches = _specifierTokenRegex . Matches ( format ) ;
89
+ var indexTokenMatches = _argumentIndexRegex . Matches ( format ) ;
90
+ var memberNameMatches = _objectMemberRegex . Matches ( format ) ;
91
+
92
+ if ( memberNameMatches . Count > 0 && values . Length == 1 )
93
+ {
94
+ format = FormatString ( format , FormatTokenFlags . MemberToken , values ) ;
95
+ }
96
+ else
97
+ {
98
+ if ( indexTokenMatches . Count > 0 )
99
+ {
100
+ format = FormatString ( format , FormatTokenFlags . IndexToken , values ) ;
101
+ }
102
+
103
+ if ( specifierTokenMatches . Count > 0 )
104
+ {
105
+ format = FormatString ( format , FormatTokenFlags . SpecifierToken , values ) ;
106
+ }
107
+ }
108
+ return format ;
109
+ }
110
+
111
+ /// <summary>
112
+ /// The Function which does all the heavy lifting.
113
+ /// </summary>
114
+ /// <param name="format">A composite format string</param>
115
+ /// <param name="flags">The flags which specify how the <paramref name="format" /> string should be interpreted.</param>
116
+ /// <param name="arguments">The arguments to format the <paramref name="format" /> parameter with.</param>
117
+ /// <returns>System.String.</returns>
118
+ public static string FormatString ( string format , FormatTokenFlags flags , params object [ ] arguments )
119
+ {
120
+ switch ( flags )
121
+ {
122
+ case FormatTokenFlags . IndexToken :
123
+ return string . Format ( format , arguments ) ;
124
+
125
+ case FormatTokenFlags . SpecifierToken :
126
+ var stringBuilder = new StringBuilder ( ) ;
127
+ for ( int i = 0 ,
128
+ argIndex = 0 ; i < format . Length ; i ++ )
129
+ {
130
+ stringBuilder . Append ( format [ i ] == '%' && argIndex < arguments . Length ? "{" + argIndex ++ + "}" : format . Substring ( i , 1 ) ) ;
131
+ }
132
+ return string . Format ( stringBuilder . ToString ( ) , arguments ) ;
133
+
134
+ case FormatTokenFlags . MemberToken :
135
+ return string . Format ( _regexReformatter ( name => ( name == "0" ) ? arguments [ 0 ] : DataBinder . Eval ( arguments [ 0 ] , name ) , format , arguments ) , arguments ) ;
136
+
137
+ default :
138
+ return format ;
139
+ }
140
+ }
141
+
142
+ public static void Initialize ( )
143
+ {
144
+ const RegexOptions regexOptions = RegexOptions . Compiled | RegexOptions . CultureInvariant ;
145
+ _objectMemberRegex = new Regex ( @"(?<start>(\{))+(?<property>[\w\.]+)(?<end>(\}))+" , regexOptions ) ;
146
+ _specifierTokenRegex = new Regex ( @"(?<!\\)%" , regexOptions ) ;
147
+ _argumentIndexRegex = new Regex ( @"\{(\d)\}" , regexOptions ) ;
148
+ _regexReformatter = ( valueFetcher , format , parameters ) =>
149
+ {
150
+ var argumentCollection = new List < object > ( ) ;
151
+ var rewrittenFormat = _objectMemberRegex . Replace ( format , match =>
152
+ {
153
+ Group startGroup = match . Groups [ "start" ] ,
154
+ propertyGroup = match . Groups [ "property" ] ,
155
+ endGroup = match . Groups [ "end" ] ;
156
+
157
+ var result = valueFetcher ( propertyGroup . Value ) ;
158
+
159
+ argumentCollection . Add ( result ) ;
160
+ var index = argumentCollection . Count - 1 ;
161
+ var fmt = new string ( '{' , startGroup . Captures . Count ) + index + new string ( '}' , endGroup . Captures . Count ) ;
162
+ return string . Format ( fmt , argumentCollection . ToArray ( ) ) ;
163
+ } ) ;
164
+
165
+ return rewrittenFormat ;
166
+ } ;
167
+ }
168
+ }
169
+ }
0 commit comments