2 // System.Globalization.StringInfo.cs
5 // Dick Porter (dick@ximian.com)
7 // (C) 2002 Ximian, Inc.
8 // (C) 2004 Novell, Inc.
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
35 using System.Runtime.InteropServices;
37 namespace System.Globalization {
43 public class StringInfo {
52 public StringInfo (string value)
54 // Argument check in property
59 public override bool Equals (object value)
61 StringInfo other = value as StringInfo;
62 return other != null && s == other.s;
66 public override int GetHashCode ()
68 return s.GetHashCode ();
71 public int LengthInTextElements {
75 for (int idx = 0; idx < s.Length; length++)
76 idx += GetNextTextElementLength (s, idx);
82 public string String {
86 throw new ArgumentNullException ("value");
92 public string SubstringByTextElements (int startingTextElement)
94 if (startingTextElement < 0 || s.Length == 0)
95 throw new ArgumentOutOfRangeException ("startingTextElement");
97 for (int i = 0; i < startingTextElement; i++) {
99 throw new ArgumentOutOfRangeException ("startingTextElement");
100 idx += GetNextTextElementLength (s, idx);
102 return s.Substring (idx);
105 public string SubstringByTextElements (int startingTextElement, int lengthInTextElements)
107 if (startingTextElement < 0 || s.Length == 0)
108 throw new ArgumentOutOfRangeException ("startingTextElement");
109 if (lengthInTextElements < 0)
110 throw new ArgumentOutOfRangeException ("lengthInTextElements");
112 for (int i = 0; i < startingTextElement; i++) {
114 throw new ArgumentOutOfRangeException ("startingTextElement");
115 idx += GetNextTextElementLength (s, idx);
118 for (int i = 0; i < lengthInTextElements; i++) {
120 throw new ArgumentOutOfRangeException ("lengthInTextElements");
121 idx += GetNextTextElementLength (s, idx);
123 return s.Substring (start, idx - start);
127 public static string GetNextTextElement(string str)
129 if(str == null || str.Length == 0) {
130 throw new ArgumentNullException("string is null");
132 return(GetNextTextElement (str, 0));
135 public static string GetNextTextElement(string str, int index)
137 int len = GetNextTextElementLength (str, index);
138 return len != 1 ? str.Substring (index, len) : new string (str [index], 1);
141 static int GetNextTextElementLength(string str, int index)
144 throw new ArgumentNullException("string is null");
148 if(index >= str.Length)
152 if(index < 0 || index >= str.Length)
154 throw new ArgumentOutOfRangeException ("Index is not valid");
156 /* Find the next base character, surrogate
157 * pair or combining character sequence
160 char ch = str[index];
161 UnicodeCategory cat = char.GetUnicodeCategory (ch);
163 if (cat == UnicodeCategory.Surrogate) {
164 /* Check that it's a high surrogate
165 * followed by a low surrogate
167 if (ch >= 0xD800 && ch <= 0xDBFF) {
168 if ((index + 1) < str.Length &&
169 str[index + 1] >= 0xDC00 &&
170 str[index + 1] <= 0xDFFF) {
171 /* A valid surrogate pair */
174 /* High surrogate on its own */
178 /* Low surrogate on its own */
182 /* Look for a base character, which
183 * may or may not be followed by a
184 * series of combining characters
187 if (cat == UnicodeCategory.NonSpacingMark ||
188 cat == UnicodeCategory.SpacingCombiningMark ||
189 cat == UnicodeCategory.EnclosingMark) {
190 /* Not a base character */
196 while (index + count < str.Length) {
197 cat = char.GetUnicodeCategory (str[index + count]);
198 if (cat != UnicodeCategory.NonSpacingMark &&
199 cat != UnicodeCategory.SpacingCombiningMark &&
200 cat != UnicodeCategory.EnclosingMark) {
201 /* Finished the sequence */
211 public static TextElementEnumerator GetTextElementEnumerator(string str)
213 if(str == null || str.Length == 0) {
214 throw new ArgumentNullException("string is null");
216 return(new TextElementEnumerator (str, 0));
219 public static TextElementEnumerator GetTextElementEnumerator(string str, int index)
222 throw new ArgumentNullException("string is null");
225 if(index < 0 || index >= str.Length) {
226 throw new ArgumentOutOfRangeException ("Index is not valid");
229 return(new TextElementEnumerator (str, index));
232 public static int[] ParseCombiningCharacters(string str)
235 throw new ArgumentNullException("string is null");
238 ArrayList indices = new ArrayList (str.Length);
239 TextElementEnumerator tee = GetTextElementEnumerator (str);
242 while(tee.MoveNext ()) {
243 indices.Add (tee.ElementIndex);
246 return((int[])indices.ToArray (typeof (int)));