33// See the LICENSE file in the project root for more information.
44
55using System ;
6+ using System . Diagnostics . Contracts ;
67using System . Globalization ;
7- using System . Linq ;
88using System . Numerics ;
99
1010namespace Microsoft . Toolkit . Uwp . UI
@@ -15,157 +15,191 @@ namespace Microsoft.Toolkit.Uwp.UI
1515 public static class StringExtensions
1616 {
1717 /// <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).
1922 /// </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 )
2328 {
24- try
29+ if ( text . Length > 0 )
2530 {
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 ] == '>' )
2835 {
29- throw new Exception ( ) ;
36+ text = text . Substring ( 1 , text . Length - 2 ) ;
3037 }
31- else if ( str [ 0 ] == '<' && str [ strLength - 1 ] == '>' )
32- {
33- str = str . Substring ( 1 , strLength - 2 ) ;
34- }
35-
36- string [ ] values = str . Split ( ',' ) ;
3738
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 )
4641 {
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+ }
4846 }
4947 else
5048 {
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+ }
5259 }
53-
54- return vector ;
55- }
56- catch ( Exception )
57- {
58- throw new FormatException ( $ "Cannot convert { str } to Vector2. Use format \" float, float\" ") ;
5960 }
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\" ") ;
6065 }
6166
6267 /// <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).
6472 /// </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 )
6878 {
69- try
79+ if ( text . Length > 0 )
7080 {
71- var strLength = str . Count ( ) ;
72- if ( strLength < 1 )
81+ if ( text . Length >= 2 &&
82+ text [ 0 ] == '>' &&
83+ text [ text . Length - 1 ] == '>' )
7384 {
74- throw new Exception ( ) ;
85+ text = text . Substring ( 1 , text . Length - 2 ) ;
7586 }
76- else if ( str [ 0 ] == '<' && str [ strLength - 1 ] == '>' )
77- {
78- str = str . Substring ( 1 , strLength - 2 ) ;
79- }
80-
81- string [ ] values = str . Split ( ',' ) ;
8287
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 )
9189 {
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+ }
9694 }
9795 else
9896 {
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+ }
100108 }
101-
102- return vector ;
103- }
104- catch ( Exception )
105- {
106- throw new FormatException ( $ "Cannot convert { str } to Vector3. Use format \" float, float, float\" ") ;
107109 }
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\" ") ;
108114 }
109115
110116 /// <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).
112121 /// </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 )
116127 {
117- try
128+ if ( text . Length > 0 )
118129 {
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 ] == '>' )
125133 {
126- str = str . Substring ( 1 , strLength - 2 ) ;
134+ text = text . Substring ( 1 , text . Length - 2 ) ;
127135 }
128136
129- string [ ] values = str . Split ( ',' ) ;
130-
131- var count = values . Count ( ) ;
132- Vector4 vector ;
133-
134- if ( count == 1 )
137+ if ( text . IndexOf ( ',' ) == - 1 )
135138 {
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+ }
145143 }
146144 else
147145 {
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+ }
149158 }
150-
151- return vector ;
152- }
153- catch ( Exception )
154- {
155- throw new FormatException ( $ "Cannot convert { str } to Vector4. Use format \" float, float, float, float\" ") ;
156159 }
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\" ") ;
157164 }
158165
159166 /// <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).
161170 /// </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 )
165176 {
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 ) ;
167201
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 \" " ) ;
169203 }
170204 }
171205}
0 commit comments