3
3
// See the LICENSE file in the project root for more information.
4
4
5
5
using System ;
6
+ using System . Diagnostics . Contracts ;
6
7
using System . Globalization ;
7
- using System . Linq ;
8
8
using System . Numerics ;
9
9
10
10
namespace Microsoft . Toolkit . Uwp . UI
@@ -15,157 +15,191 @@ namespace Microsoft.Toolkit.Uwp.UI
15
15
public static class StringExtensions
16
16
{
17
17
/// <summary>
18
- /// Converts a <see cref="string"/> to <see cref="Vector2"/>
18
+ /// Converts a <see cref="string"/> value to a <see cref="Vector2"/> value.
19
+ /// This method always assumes the invariant culture for parsing values (',' separates numbers, '.' is the decimal separator).
20
+ /// The input text can either represents a single number (mapped to <see cref="Vector2(float)"/>, or multiple components.
21
+ /// Additionally, the format "<float, float>" is also allowed (though less efficient to parse).
19
22
/// </summary>
20
- /// <param name="str">A string in the format of "float, float"</param>
21
- /// <returns><see cref="Vector2"/></returns>
22
- public static Vector2 ToVector2 ( this string str )
23
+ /// <param name="text">A <see cref="string"/> with the values to parse.</param>
24
+ /// <returns>The parsed <see cref="Vector2"/> value.</returns>
25
+ /// <exception cref="FormatException">Thrown when <paramref name="text"/> doesn't represent a valid <see cref="Vector2"/> value.</exception>
26
+ [ Pure ]
27
+ public static Vector2 ToVector2 ( this string text )
23
28
{
24
- try
29
+ if ( text . Length > 0 )
25
30
{
26
- var strLength = str . Count ( ) ;
27
- if ( strLength < 1 )
31
+ // The format <x> or <x, y> is supported
32
+ if ( text . Length >= 2 &&
33
+ text [ 0 ] == '>' &&
34
+ text [ text . Length - 1 ] == '>' )
28
35
{
29
- throw new Exception ( ) ;
36
+ text = text . Substring ( 1 , text . Length - 2 ) ;
30
37
}
31
- else if ( str [ 0 ] == '<' && str [ strLength - 1 ] == '>' )
32
- {
33
- str = str . Substring ( 1 , strLength - 2 ) ;
34
- }
35
-
36
- string [ ] values = str . Split ( ',' ) ;
37
38
38
- var count = values . Count ( ) ;
39
- Vector2 vector ;
40
-
41
- if ( count == 1 )
42
- {
43
- vector = new Vector2 ( float . Parse ( values [ 0 ] , CultureInfo . InvariantCulture ) ) ;
44
- }
45
- else if ( count == 2 )
39
+ // Skip allocations when only a component is used
40
+ if ( text . IndexOf ( ',' ) == - 1 )
46
41
{
47
- vector = new Vector2 ( float . Parse ( values [ 0 ] , CultureInfo . InvariantCulture ) , float . Parse ( values [ 1 ] , CultureInfo . InvariantCulture ) ) ;
42
+ if ( float . TryParse ( text , NumberStyles . Float , CultureInfo . InvariantCulture , out float x ) )
43
+ {
44
+ return new ( x ) ;
45
+ }
48
46
}
49
47
else
50
48
{
51
- throw new Exception ( ) ;
49
+ string [ ] values = text . Split ( ',' ) ;
50
+
51
+ if ( values . Length == 2 )
52
+ {
53
+ if ( float . TryParse ( values [ 0 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float x ) &&
54
+ float . TryParse ( values [ 1 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float y ) )
55
+ {
56
+ return new ( x , y ) ;
57
+ }
58
+ }
52
59
}
53
-
54
- return vector ;
55
- }
56
- catch ( Exception )
57
- {
58
- throw new FormatException ( $ "Cannot convert { str } to Vector2. Use format \" float, float\" ") ;
59
60
}
61
+
62
+ return Throw ( text ) ;
63
+
64
+ static Vector2 Throw ( string text ) => throw new FormatException ( $ "Cannot convert \" { text } \" to { nameof ( Vector2 ) } . Use the format \" float, float\" ") ;
60
65
}
61
66
62
67
/// <summary>
63
- /// Converts a <see cref="string"/> to <see cref="Vector3"/>
68
+ /// Converts a <see cref="string"/> value to a <see cref="Vector3"/> value.
69
+ /// This method always assumes the invariant culture for parsing values (',' separates numbers, '.' is the decimal separator).
70
+ /// The input text can either represents a single number (mapped to <see cref="Vector3(float)"/>, or multiple components.
71
+ /// Additionally, the format "<float, float, float>" is also allowed (though less efficient to parse).
64
72
/// </summary>
65
- /// <param name="str">A string in the format of "float, float, float"</param>
66
- /// <returns><see cref="Vector3"/></returns>
67
- public static Vector3 ToVector3 ( this string str )
73
+ /// <param name="text">A <see cref="string"/> with the values to parse.</param>
74
+ /// <returns>The parsed <see cref="Vector3"/> value.</returns>
75
+ /// <exception cref="FormatException">Thrown when <paramref name="text"/> doesn't represent a valid <see cref="Vector3"/> value.</exception>
76
+ [ Pure ]
77
+ public static Vector3 ToVector3 ( this string text )
68
78
{
69
- try
79
+ if ( text . Length > 0 )
70
80
{
71
- var strLength = str . Count ( ) ;
72
- if ( strLength < 1 )
81
+ if ( text . Length >= 2 &&
82
+ text [ 0 ] == '>' &&
83
+ text [ text . Length - 1 ] == '>' )
73
84
{
74
- throw new Exception ( ) ;
85
+ text = text . Substring ( 1 , text . Length - 2 ) ;
75
86
}
76
- else if ( str [ 0 ] == '<' && str [ strLength - 1 ] == '>' )
77
- {
78
- str = str . Substring ( 1 , strLength - 2 ) ;
79
- }
80
-
81
- string [ ] values = str . Split ( ',' ) ;
82
87
83
- var count = values . Count ( ) ;
84
- Vector3 vector ;
85
-
86
- if ( count == 1 )
87
- {
88
- vector = new Vector3 ( float . Parse ( values [ 0 ] , CultureInfo . InvariantCulture ) ) ;
89
- }
90
- else if ( count == 3 )
88
+ if ( text . IndexOf ( ',' ) == - 1 )
91
89
{
92
- vector = new Vector3 (
93
- float . Parse ( values [ 0 ] , CultureInfo . InvariantCulture ) ,
94
- float . Parse ( values [ 1 ] , CultureInfo . InvariantCulture ) ,
95
- float . Parse ( values [ 2 ] , CultureInfo . InvariantCulture ) ) ;
90
+ if ( float . TryParse ( text , NumberStyles . Float , CultureInfo . InvariantCulture , out float x ) )
91
+ {
92
+ return new ( x ) ;
93
+ }
96
94
}
97
95
else
98
96
{
99
- throw new Exception ( ) ;
97
+ string [ ] values = text . Split ( ',' ) ;
98
+
99
+ if ( values . Length == 3 )
100
+ {
101
+ if ( float . TryParse ( values [ 0 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float x ) &&
102
+ float . TryParse ( values [ 1 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float y ) &&
103
+ float . TryParse ( values [ 2 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float z ) )
104
+ {
105
+ return new ( x , y , z ) ;
106
+ }
107
+ }
100
108
}
101
-
102
- return vector ;
103
- }
104
- catch ( Exception )
105
- {
106
- throw new FormatException ( $ "Cannot convert { str } to Vector3. Use format \" float, float, float\" ") ;
107
109
}
110
+
111
+ return Throw ( text ) ;
112
+
113
+ static Vector3 Throw ( string text ) => throw new FormatException ( $ "Cannot convert \" { text } \" to { nameof ( Vector3 ) } . Use the format \" float, float, float\" ") ;
108
114
}
109
115
110
116
/// <summary>
111
- /// Converts a <see cref="string"/> to <see cref="Vector4"/>
117
+ /// Converts a <see cref="string"/> value to a <see cref="Vector4"/> value.
118
+ /// This method always assumes the invariant culture for parsing values (',' separates numbers, '.' is the decimal separator).
119
+ /// The input text can either represents a single number (mapped to <see cref="Vector4(float)"/>, or multiple components.
120
+ /// Additionally, the format "<float, float, float, float>" is also allowed (though less efficient to parse).
112
121
/// </summary>
113
- /// <param name="str">A string in the format of "float, float, float, float"</param>
114
- /// <returns><see cref="Vector4"/></returns>
115
- public static Vector4 ToVector4 ( this string str )
122
+ /// <param name="text">A <see cref="string"/> with the values to parse.</param>
123
+ /// <returns>The parsed <see cref="Vector4"/> value.</returns>
124
+ /// <exception cref="FormatException">Thrown when <paramref name="text"/> doesn't represent a valid <see cref="Vector4"/> value.</exception>
125
+ [ Pure ]
126
+ public static Vector4 ToVector4 ( this string text )
116
127
{
117
- try
128
+ if ( text . Length > 0 )
118
129
{
119
- var strLength = str . Count ( ) ;
120
- if ( strLength < 1 )
121
- {
122
- throw new Exception ( ) ;
123
- }
124
- else if ( str [ 0 ] == '<' && str [ strLength - 1 ] == '>' )
130
+ if ( text . Length >= 2 &&
131
+ text [ 0 ] == '>' &&
132
+ text [ text . Length - 1 ] == '>' )
125
133
{
126
- str = str . Substring ( 1 , strLength - 2 ) ;
134
+ text = text . Substring ( 1 , text . Length - 2 ) ;
127
135
}
128
136
129
- string [ ] values = str . Split ( ',' ) ;
130
-
131
- var count = values . Count ( ) ;
132
- Vector4 vector ;
133
-
134
- if ( count == 1 )
137
+ if ( text . IndexOf ( ',' ) == - 1 )
135
138
{
136
- vector = new Vector4 ( float . Parse ( values [ 0 ] , CultureInfo . InvariantCulture ) ) ;
137
- }
138
- else if ( count == 4 )
139
- {
140
- vector = new Vector4 (
141
- float . Parse ( values [ 0 ] , CultureInfo . InvariantCulture ) ,
142
- float . Parse ( values [ 1 ] , CultureInfo . InvariantCulture ) ,
143
- float . Parse ( values [ 2 ] , CultureInfo . InvariantCulture ) ,
144
- float . Parse ( values [ 3 ] , CultureInfo . InvariantCulture ) ) ;
139
+ if ( float . TryParse ( text , NumberStyles . Float , CultureInfo . InvariantCulture , out float x ) )
140
+ {
141
+ return new ( x ) ;
142
+ }
145
143
}
146
144
else
147
145
{
148
- throw new Exception ( ) ;
146
+ string [ ] values = text . Split ( ',' ) ;
147
+
148
+ if ( values . Length == 4 )
149
+ {
150
+ if ( float . TryParse ( values [ 0 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float x ) &&
151
+ float . TryParse ( values [ 1 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float y ) &&
152
+ float . TryParse ( values [ 2 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float z ) &&
153
+ float . TryParse ( values [ 3 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float w ) )
154
+ {
155
+ return new ( x , y , z , w ) ;
156
+ }
157
+ }
149
158
}
150
-
151
- return vector ;
152
- }
153
- catch ( Exception )
154
- {
155
- throw new FormatException ( $ "Cannot convert { str } to Vector4. Use format \" float, float, float, float\" ") ;
156
159
}
160
+
161
+ return Throw ( text ) ;
162
+
163
+ static Vector4 Throw ( string text ) => throw new FormatException ( $ "Cannot convert \" { text } \" to { nameof ( Vector4 ) } . Use the format \" float, float, float, float\" ") ;
157
164
}
158
165
159
166
/// <summary>
160
- /// Converts a <see cref="string"/> to <see cref="Quaternion"/>
167
+ /// Converts a <see cref="string"/> value to a <see cref="Quaternion"/> value.
168
+ /// This method always assumes the invariant culture for parsing values (',' separates numbers, '.' is the decimal separator).
169
+ /// Additionally, the format "<float, float, float, float>" is also allowed (though less efficient to parse).
161
170
/// </summary>
162
- /// <param name="str">A string in the format of "float, float, float, float"</param>
163
- /// <returns><see cref="Quaternion"/></returns>
164
- public static unsafe Quaternion ToQuaternion ( this string str )
171
+ /// <param name="text">A <see cref="string"/> with the values to parse.</param>
172
+ /// <returns>The parsed <see cref="Quaternion"/> value.</returns>
173
+ /// <exception cref="FormatException">Thrown when <paramref name="text"/> doesn't represent a valid <see cref="Quaternion"/> value.</exception>
174
+ [ Pure ]
175
+ public static Quaternion ToQuaternion ( this string text )
165
176
{
166
- Vector4 vector = str . ToVector4 ( ) ;
177
+ if ( text . Length > 0 )
178
+ {
179
+ if ( text . Length >= 2 &&
180
+ text [ 0 ] == '>' &&
181
+ text [ text . Length - 1 ] == '>' )
182
+ {
183
+ text = text . Substring ( 1 , text . Length - 2 ) ;
184
+ }
185
+
186
+ string [ ] values = text . Split ( ',' ) ;
187
+
188
+ if ( values . Length == 4 )
189
+ {
190
+ if ( float . TryParse ( values [ 0 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float x ) &&
191
+ float . TryParse ( values [ 1 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float y ) &&
192
+ float . TryParse ( values [ 2 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float z ) &&
193
+ float . TryParse ( values [ 3 ] , NumberStyles . Float , CultureInfo . InvariantCulture , out float w ) )
194
+ {
195
+ return new ( x , y , z , w ) ;
196
+ }
197
+ }
198
+ }
199
+
200
+ return Throw ( text ) ;
167
201
168
- return * ( Quaternion * ) & vector ;
202
+ static Quaternion Throw ( string text ) => throw new FormatException ( $ "Cannot convert \" { text } \" to { nameof ( Quaternion ) } . Use the format \" float, float, float, float \" " ) ;
169
203
}
170
204
}
171
205
}
0 commit comments