source: Include/Classes/System/String.ab@ 227

Last change on this file since 227 was 227, checked in by dai, 17 years ago

文字列の比較演算子の戻り値がLong型になっていたので、Booleanに修正した。
String.GetTypeのテストケースを修正。

File size: 17.1 KB
Line 
1' Classes/System/String.ab
2
3#require <basic/function.sbp>
4
5#ifdef __STRING_IS_NOT_ALWAYS_UNICODE
6TypeDef StrChar = Char
7#ifndef UNICODE
8#define __STRING_IS_NOT_UNICODE
9#endif
10#else
11TypeDef StrChar = WCHAR
12#ifndef UNICODE
13#define __STRING_UNICODE_WINDOWS_ANSI
14#endif
15#endif
16
17Class String
18' Inherits IComparable, ICloneable, IConvertible, IEnumerable
19
20 m_Length As Long
21Public
22 Chars As *StrChar
23
24 Sub String()
25 Chars = _System_malloc(SizeOf (StrChar))
26 Chars[0] = 0
27 m_Length = 0
28 End Sub
29
30 Sub String(initStr As PCSTR)
31 Assign(initStr)
32 End Sub
33
34 Sub String(initStr As PCSTR, length As Long)
35 Assign(initStr, length)
36 End Sub
37
38 Sub String(initStr As PCWSTR)
39 Assign(initStr)
40 End Sub
41
42 Sub String(initStr As PCWSTR, length As Long)
43 Assign(initStr, length)
44 End Sub
45
46 Sub String(ByRef initStr As String)
47 Assign(initStr)
48 End Sub
49
50 Sub String(length As Long)
51 ReSize(length)
52 End Sub
53
54 Sub String(initChar As StrChar, length As Long)
55 ReSize(length, initChar)
56 End Sub
57
58 Sub ~String()
59 _System_free(Chars)
60 Chars = 0
61#ifdef _DEBUG
62 m_Length = 0
63#endif
64 End Sub
65
66 Const Function Length() As Long
67 Return m_Length
68 End Function
69
70 Function Operator() As *StrChar
71 Return Chars
72 End Function
73
74 Const Function Operator [] (n As Long) As StrChar
75#ifdef _DEBUG
76 If n > Length Then
77 'Throw ArgumentOutOfRangeException
78 Debug
79 End If
80#endif
81 Return Chars[n]
82 End Function
83
84 Sub Operator []= (n As Long, c As StrChar)
85#ifdef _DEBUG
86 If n >= Length Then
87 'Throw ArgumentOutOfRangeException
88 Debug
89 End If
90#endif
91 Chars[n] = c
92 End Sub
93
94/* Const Function Operator + (text As *Byte) As String
95 Return Concat(text As PCTSTR, lstrlen(text))
96 End Function*/
97
98 Const Function Operator + (text As PCSTR) As String
99 Return Concat(text, lstrlenA(text))
100 End Function
101
102 Const Function Operator + (text As PCWSTR) As String
103 Return Concat(text, lstrlenW(text))
104 End Function
105
106 Const Function Operator + (objString As String) As String
107 Return Concat(objString.Chars, objString.m_Length)
108 End Function
109
110 Const Function Operator & (text As PCSTR) As String
111 Dim tempString = This + text
112 Return tempString
113 End Function
114
115 Const Function Operator & (text As PCWSTR) As String
116 Dim tempString = This + text
117 Return tempString
118 End Function
119
120 Const Function Operator & (objString As String) As String
121 Dim tempString = This + objString
122 Return tempString
123 End Function
124
125 Const Function Operator == (objString As String) As Boolean
126 Return String.Compare(This, objString) = 0
127 End Function
128
129 Const Function Operator == (text As *StrChar) As Boolean
130 Return _System_StrCmp(This.Chars, text) = 0
131 End Function
132
133 Const Function Operator <> (objString As String) As Boolean
134 Return String.Compare(This, objString) <> 0
135 End Function
136
137 Const Function Operator <> (text As *StrChar) As Boolean
138 Return _System_StrCmp(This.Chars, text) <> 0
139 End Function
140
141 Const Function Operator < (objString As String) As Boolean
142 Return String.Compare(This, objString) < 0
143 End Function
144
145 Const Function Operator < (text As *StrChar) As Boolean
146 Return _System_StrCmp(This.Chars, text) < 0
147 End Function
148
149 Const Function Operator > (objString As String) As Boolean
150 Return String.Compare(This, objString) > 0
151 End Function
152
153 Const Function Operator > (text As *StrChar) As Boolean
154 Return _System_StrCmp(This.Chars, text) > 0
155 End Function
156
157 Const Function Operator <= (objString As String) As Boolean
158 Return String.Compare(This, objString) <= 0
159 End Function
160
161 Const Function Operator <= (text As *StrChar) As Boolean
162 Return _System_StrCmp(This.Chars, text) <= 0
163 End Function
164
165 Const Function Operator >= (objString As String) As Boolean
166 Return String.Compare(This, objString) >= 0
167 End Function
168
169 Const Function Operator >= (text As *StrChar) As Boolean
170 Return _System_StrCmp(This.Chars, text) >= 0
171 End Function
172
173 Static Function Compare(x As String, y As String) As Long
174 Return CompareOrdinal(x, y)
175 End Function
176
177 Static Function Compare(x As String, indexX As Long, y As String, indexY As Long, length As Long) As Long
178 Return CompareOrdinal(x, indexX, y, indexY, length)
179 End Function
180
181 Static Function CompareOrdinal(x As String, y As String) As Long
182 Return _System_StrCmp(x.Chars, y.Chars)
183 End Function
184
185 Static Function CompareOrdinal(x As String, indexX As Long, y As String, indexY As Long, length As Long) As Long
186 If x = Nothing Then
187 If y = Nothing Then
188 Return 0
189 Else
190 Return -1
191 End If
192 ElseIf y = Nothing Then
193 Return 1
194 End If
195 Return _System_StrCmpN(VarPtr(x.Chars[indexX]), VarPtr(y.Chars[indexY]), length)
196 End Function
197
198 Function CompareTo(y As String) As Long
199 Return String.Compare(This, y)
200 End Function
201
202 Function CompareTo(y As Object) As Long
203 Dim s = y As String
204' If y is not String Then
205' Throw New ArgumentException
206' End If
207 Return CompareTo(y)
208 End Function
209
210 Const Function StrPtr() As *StrChar
211 Return Chars
212 End Function
213
214 Sub ReSize(allocLength As Long)
215 If allocLength < 0 Then Exit Sub
216 If allocLength > m_Length Then
217 Dim oldLength As Long
218 oldLength = m_Length
219 If AllocStringBuffer(allocLength) <> 0 Then
220 ZeroMemory(VarPtr(Chars[oldLength]), SizeOf (StrChar) * (m_Length - oldLength + 1))
221 End If
222 Else
223 m_Length = allocLength
224 Chars[m_Length] = 0
225 End If
226 End Sub
227
228 Sub ReSize(allocLength As Long, c As StrChar)
229 If allocLength < 0 Then
230 Exit Sub
231 ElseIf allocLength > m_Length Then
232 Dim oldLength As Long
233 oldLength = m_Length
234 If AllocStringBuffer(allocLength) <> 0 Then
235 Dim p = VarPtr(Chars[oldLength]) As *StrChar
236 Dim fillLen = m_Length - oldLength
237 Dim i As Long
238 For i = 0 To ELM(fillLen)
239 p[i] = c
240 Next
241 End If
242 Else
243 m_Length = allocLength
244 End If
245 Chars[m_Length] = 0
246 End Sub
247
248 Sub Assign(text As PCSTR, textLengthA As Long)
249#ifdef __STRING_IS_NOT_UNICODE
250 AssignFromStrChar(text, textLengthA)
251#else
252 Dim textLengthW = MultiByteToWideChar(CP_THREAD_ACP, 0, text, textLengthA, 0, 0)
253 If AllocStringBuffer(textLengthW) <> 0 Then
254 MultiByteToWideChar(CP_THREAD_ACP, 0, text, textLengthA, Chars, textLengthW)
255 Chars[textLengthW] = 0
256 End If
257#endif
258 End Sub
259
260 Sub Assign(text As PCWSTR, textLengthW As Long)
261#ifdef __STRING_IS_NOT_UNICODE
262 Dim textLengthA = WideCharToMultiByte(CP_THREAD_ACP, 0, text, textLengthW, 0, 0, 0, 0)
263 If AllocStringBuffer(textLengthA) <> 0 Then
264 WideCharToMultiByte(CP_THREAD_ACP, 0, text, textLengthW, Chars, textLengthA, 0, 0)
265 Chars[textLengthA] = 0
266 End If
267#else
268 AssignFromStrChar(text, textLengthW)
269#endif
270 End Sub
271
272 Sub Assign(ByRef objString As String)
273 Assign(objString.Chars, objString.m_Length)
274 End Sub
275
276 Sub Assign(text As PCSTR)
277 If text Then
278 Assign(text, lstrlenA(text))
279 Else
280 If Chars <> 0 Then
281 Chars[0] = 0
282 End If
283 m_Length = 0
284 End If
285 End Sub
286
287 Sub Assign(text As PCWSTR)
288 If text Then
289 Assign(text, lstrlenW(text))
290 Else
291 If Chars <> 0 Then
292 Chars[0] = 0
293 End If
294 m_Length = 0
295 End If
296 End Sub
297
298 Sub Append(text As *StrChar, textLength As Long)
299 Dim prevLen As Long
300 prevLen = m_Length
301 If AllocStringBuffer(m_Length + textLength) <> 0 Then
302 memcpy(VarPtr(Chars[prevLen]), text, SizeOf (StrChar) * textLength)
303 Chars[m_Length] = 0
304 End If
305 End Sub
306
307 Sub Append(text As *StrChar)
308 Append(text, lstrlen(text))
309 End Sub
310
311 Sub Append(ByRef str As String)
312 Append(str.Chars, str.m_Length)
313 End Sub
314
315 Const Function Clone() As String
316 Return This
317 End Function
318Private
319 Static Function ConcatStrChar(text1 As *StrChar, text1Length As Long, text2 As *StrChar, text2Length As Long) As String
320 ConcatStrChar = New String()
321 With ConcatStrChar
322 .AllocStringBuffer(text1Length + text2Length)
323 memcpy(.Chars, text1, SizeOf (StrChar) * text1Length)
324 memcpy(VarPtr(.Chars[text1Length]), text2, SizeOf (StrChar) * text2Length)
325 .Chars[text1Length + text2Length] = 0
326 End With
327 End Function
328Public
329 Const Function Concat(text As PCSTR, len As Long) As String
330#ifdef __STRING_IS_NOT_UNICODE
331 Return ConcatStrChar(This.Chars, m_Length, text, len)
332#else
333 With Concat
334 Dim lenW = MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, 0, 0)
335 .AllocStringBuffer(m_Length + lenW)
336 memcpy(.Chars, This.Chars, m_Length)
337 MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, VarPtr(.Chars[m_Length]), lenW)
338 .Chars[m_Length + lenW] = 0
339 End With
340#endif
341 End Function
342
343 Const Function Concat(text As PCWSTR, len As Long) As String
344#ifdef __STRING_IS_NOT_UNICODE
345 With Concat
346 Dim lenA = MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, 0, 0, 0, 0)
347 .AllocStringBuffer(m_Length + lenA)
348 memcpy(.Chars, This.Chars, m_Length)
349 MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, VarPtr(.Chars[m_Length]), lenA, 0, 0)
350 .Chars[m_Length + lenA] = 0
351 End With
352#else
353 Return ConcatStrChar(This.Chars, m_Length, text, len)
354#endif
355 End Function
356
357 Static Function Concat(x As String, y As String) As String
358 If String.IsNullOrEmpty(x) Then
359 Return y
360 Else
361 Return x.Concat(y.Chars, y.m_Length)
362 End If
363 End Function
364
365 Static Function Concat(x As Object, y As Object) As String
366 Return String.Concat(x.ToString, y.ToString)
367 End Function
368
369 Const Function Contains(objString As String) As Boolean
370 Return IndexOf(objString, 0, m_Length) >= 0
371 End Function
372
373 Const Function Contains(lpszText As *StrChar) As Boolean
374 Return IndexOf(lpszText, 0, m_Length) >= 0
375 End Function
376
377 Const Function IndexOf(lpszText As *StrChar) As Long
378 Return IndexOf(lpszText, 0, m_Length)
379 End Function
380
381 Const Function IndexOf(lpszText As *StrChar, startIndex As Long) As Long
382 Return IndexOf(lpszText, startIndex, m_Length - startIndex)
383 End Function
384
385 Const Function IndexOf(lpszText As *StrChar, startIndex As Long, count As Long) As Long
386 Dim length = lstrlen(lpszText)
387
388 If startIndex < 0 Then Return -1
389 If count < 1 Or count + startIndex > m_Length Then Return -1
390 If length > m_Length Then Return -1
391
392 If length = 0 Then Return startIndex
393
394 Dim i As Long, j As Long
395 For i = startIndex To startIndex + count - 1
396 For j = 0 To length - 1
397 If Chars[i + j] = lpszText[j] Then
398 If j = length - 1 Then Return i
399 Else
400 Exit For
401 End If
402 Next
403 Next
404 Return -1
405 End Function
406
407 Const Function LastIndexOf(lpszText As *StrChar) As Long
408 Return LastIndexOf(lpszText, m_Length - 1, m_Length)
409 End Function
410
411 Const Function LastIndexOf(lpszText As *StrChar, startIndex As Long) As Long
412 Return LastIndexOf(lpszText As *StrChar, startIndex, startIndex + 1)
413 End Function
414
415 Const Function LastIndexOf(lpszText As *StrChar, startIndex As Long, count As Long) As Long
416 Dim length = lstrlen(lpszText)
417
418 If startIndex < 0 Or startIndex > m_Length - 1 Then Return -1
419 If count < 1 Or count > startIndex + 2 Then Return -1
420 If length > m_Length Then Return -1
421
422 If length = 0 Then Return startIndex
423
424 Dim i As Long, j As Long
425 For i = startIndex To startIndex - count + 1 Step -1
426 For j = length - 1 To 0 Step -1
427 If Chars[i + j] = lpszText[j] Then
428 If j = 0 Then Return i
429 Else
430 Exit For
431 End If
432 Next
433 Next
434 Return -1
435 End Function
436
437 Const Function StartsWith(lpszText As *StrChar) As Boolean
438 Return IndexOf(lpszText) = 0
439 End Function
440
441 Const Function EndsWith(lpszText As *StrChar) As Boolean
442 Return LastIndexOf(lpszText) = m_Length - lstrlen(lpszText)
443 End Function
444
445 Const Function Insert(startIndex As Long, text As String) As String
446 Return Insert(startIndex, text.Chars, text.Length)
447 End Function
448
449 Const Function Insert(startIndex As Long, text As *StrChar) As String
450 Return Insert(startIndex, text, lstrlen(text))
451 End Function
452
453 Const Function Insert(startIndex As Long, text As *StrChar, length As Long) As String
454 If startIndex < 0 Or startIndex > m_Length Or length < 0 Then
455 Debug 'ArgumentOutOfRangeException
456
457 End If
458 Insert.ReSize(m_Length + length)
459 memcpy(Insert.Chars, Chars, SizeOf (StrChar) * startIndex)
460 memcpy(VarPtr(Insert.Chars[startIndex]), text, SizeOf (StrChar) * length)
461 memcpy(VarPtr(Insert.Chars[startIndex + length]), VarPtr(Chars[startIndex]), SizeOf (StrChar) * (m_Length - startIndex + 1))
462 End Function
463
464 Const Function SubString(startIndex As Long) As String
465 Return SubString(startIndex, m_Length - startIndex)
466 End Function
467
468 Const Function SubString(startIndex As Long, length As Long) As String
469 If startIndex < 0 Or length <= 0 Then Return ""
470 If startIndex + length > m_Length Then Return ""
471
472 Dim temp As String
473 temp.AllocStringBuffer(length)
474 memcpy(temp.Chars, VarPtr(Chars[startIndex]), SizeOf (StrChar) * length)
475 Chars[m_Length] = 0
476 Return temp
477 End Function
478
479 Const Function Remove(startIndex As Long) As String
480 If startIndex < 0 Or startIndex > m_Length Then
481 Debug 'ArgumentOutOfRangeException
482 End If
483
484 Remove.ReSize(startIndex)
485 memcpy(Remove.Chars, This.Chars, SizeOf (StrChar) * startIndex)
486 End Function
487
488 Const Function Remove(startIndex As Long, count As Long) As String
489 If startIndex < 0 Or count < 0 Or startIndex + count > m_Length Then
490 Debug 'ArgumentOutOfRangeException
491 End If
492
493 Remove.ReSize(m_Length - count)
494 memcpy(Remove.Chars, This.Chars, SizeOf (StrChar) * startIndex)
495 memcpy(VarPtr(Remove.Chars[startIndex]), VarPtr(This.Chars[startIndex + count]), SizeOf (StrChar) * (m_Length - startIndex - count))
496 End Function
497
498 Static Function IsNullOrEmpty(s As String) As Boolean
499 If Not Object.ReferenceEquals(s, Nothing) Then
500 If s.m_Length > 0 Then
501 Return False
502 End If
503 End If
504 Return True
505 End Function
506
507 Const Function Replace(oldChar As StrChar, newChar As StrChar) As String
508 Replace = Copy(This)
509 With Replace
510 Dim i As Long
511 For i = 0 To ELM(.m_Length)
512 If .Chars[i] = oldChar Then
513 .Chars[i] = newChar
514 End If
515 Next
516 End With
517 End Function
518
519 Const Function Replace(ByRef oldStr As String, ByRef newStr As String) As String
520' If oldStr = Nothing Then Throw ArgumentNullException
521'
522' If newStr = Nothing Then
523' Return ReplaceCore(oldStr, oldStr.m_Length, "", 0)
524' Else
525 Return ReplaceCore(oldStr, oldStr.m_Length, newStr, newStr.m_Length)
526' End If
527 End Function
528
529 Const Function Replace(oldStr As *StrChar, newStr As *StrChar)
530 If oldStr = 0 Then Debug 'Throw ArgumentNullException
531 If newStr = 0 Then newStr = ""
532 Return ReplaceCore(oldStr, lstrlen(oldStr), newStr, lstrlen(newStr)) As String
533 End Function
534
535 Const Function Replace(oldStr As *StrChar, oldLen As Long, newStr As *StrChar, newLen As Long) As String
536 If oldStr = 0 Then Debug 'Throw ArgumentNullException
537 If newStr = 0 Then
538 newStr = ""
539 newLen = 0
540 End If
541 Return ReplaceCore(oldStr, oldLen, newStr, newLen)
542 End Function
543
544 Const Function ToLower() As String
545 ToLower.ReSize(m_Length)
546 Dim i As Long
547 For i = 0 To ELM(m_Length)
548 ToLower.Chars[i] = _System_ASCII_ToLower(Chars[i])
549 Next
550 End Function
551
552 Const Function ToUpper() As String
553 ToUpper.ReSize(m_Length)
554 Dim i As Long
555 For i = 0 To ELM(m_Length)
556 ToUpper.Chars[i] = _System_ASCII_ToUpper(Chars[i])
557 Next
558 End Function
559/*
560 Sub Swap(ByRef x As String)
561 Dim tempLen As Long
562 Dim tempChars As *StrChar
563 tempLen = x.m_Length
564 tempChars = x.Chars
565 x.m_Length = This.m_Length
566 x.Chars = This.Chars
567 This.m_Length = tempLen
568 This.Chars = tempChars
569 End Sub
570*/
571 Override Function ToString() As String
572 Return This
573 End Function
574
575 Static Function Copy(s As String) As String
576 Copy.ReSize(s.m_Length)
577 memcpy(Copy.Chars, This.Chars, SizeOf (StrChar) * m_Length)
578 End Function
579
580 Override Function GetHashCode() As Long
581#ifdef __STRING_IS_NOT_UNICODE
582 Dim size = (m_Length + 1) >> 1
583#else
584 Dim size = m_Length
585#endif
586 Return _System_GetHashFromWordArray(Chars As *Word, size)
587 End Function
588Private
589 ' メモリ確保に失敗すると元の文字列は失われない。(例外安全でいう強い保障)
590 Function AllocStringBuffer(textLength As Long) As *StrChar
591 If textLength < 0 Then
592 Return 0
593 ElseIf textLength > m_Length or Chars = 0 Then
594 AllocStringBuffer = _System_realloc(Chars, SizeOf(StrChar) * (textLength + 1))
595 If AllocStringBuffer <> 0 Then
596 m_Length = textLength
597 Chars = AllocStringBuffer
598 End If
599 Else
600 m_Length = textLength
601 AllocStringBuffer = Chars
602 End If
603 End Function
604
605 Function ReplaceCore(oldStr As *StrChar, oldLen As Long, newStr As *StrChar, newLen As Long) As String
606 If oldLen = 0 Then
607 Debug 'Throw ArgumentException
608 End If
609 Dim tmp As String
610 With tmp
611 Dim current = 0 As Long
612 Do
613 Dim pos = IndexOf(oldStr, current)
614 If pos = -1 Then
615 Exit Do
616 End If
617 .Append(VarPtr(Chars[current]), pos - current)
618 .Append(newStr, newLen)
619 current = pos + oldLen
620 Loop
621 .Append(VarPtr(Chars[current]), m_Length - current)
622 End With
623 Return tmp
624 End Function
625
626 Sub AssignFromStrChar(text As *StrChar, textLength As Long)
627 If text = Chars Then Exit Sub
628 If AllocStringBuffer(textLength) <> 0 Then
629 memcpy(Chars, text, SizeOf (StrChar) * textLength)
630 Chars[m_Length] = 0
631 End If
632 End Sub
633End Class
Note: See TracBrowser for help on using the repository browser.