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

Last change on this file since 270 was 270, checked in by OverTaker, 17 years ago

SubStringのバグ修整。

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