' Classes/System/String.ab Namespace System Class String Implements /*IComparable, ICloneable, IConvertible, IComparable, IEnumerable, IEnumerable, IEquatable*/ m_Length As Long Chars As *Char Sub validPointerCheck(p As VoidPtr, size = 1 As Long) If p As ULONG_PTR < &h10000 Then Throw New ArgumentException ElseIf IsBadReadPtr(p, size As ULONG_PTR) Then Throw New ArgumentException End If End Sub Public Static Const Empty = New String Sub String() ' Chars = 0 ' m_Length = 0 End Sub Sub String(initStr As PCWSTR) validPointerCheck(initStr) Assign(initStr, lstrlenW(initStr)) End Sub Sub String(initStr As PCWSTR, length As Long) validPointerCheck(initStr, length) Assign(initStr, length) End Sub Sub String(initStr As PCWSTR, start As Long, length As Long) If start < 0 Or length Or start + length < 0 Then Throw New ArgumentOutOfRangeException("String constractor: One or more arguments are out of range value.", "start or length or both") End If validPointerCheck(initStr + start, length) Assign(initStr + start, length) End Sub Sub String(initStr As PCSTR) validPointerCheck(initStr) Assign(initStr, lstrlenA(initStr)) End Sub Sub String(initStr As PCSTR, length As Long) validPointerCheck(initStr, length) Assign(initStr, length) End Sub Sub String(initStr As PCSTR, start As Long, length As Long) If start < 0 Or length < 0 Then Throw New ArgumentOutOfRangeException("String constructor: One or more arguments are out of range value.", "start or length or both") End If validPointerCheck(initStr + start, length) Assign(initStr + start, length) End Sub Sub String(initStr As String) If Not String.IsNullOrEmpty(initStr) Then Assign(initStr.Chars, initStr.m_Length) End If End Sub Sub String(initChar As Char, length As Long) AllocStringBuffer(length) ActiveBasic.Strings.ChrFill(Chars, length, initChar) Chars[length] = 0 End Sub Sub String(sb As Text.StringBuilder) Chars = StrPtr(sb) m_Length = sb.Length sb.__Stringized() End Sub Const Function Length() As Long Return m_Length End Function Function Operator() As *Char Return Chars End Function Const Function Operator [] (n As Long) As Char rangeCheck(n) Return Chars[n] End Function Const Function Operator + (y As PCSTR) As String If y = 0 Then Return This Else Return Concat(y, lstrlenA(y)) End If End Function Const Function Operator + (y As PCWSTR) As String If y = 0 Then Return This Else Return Concat(y, lstrlenW(y)) End If End Function Const Function Operator + (y As String) As String If ActiveBasic.IsNothing(y) Then Return This Else Return Concat(y.Chars, y.m_Length) End If End Function Const Function Operator & (y As PCSTR) As String Return This + y End Function Const Function Operator & (y As PCWSTR) As String Return This + y End Function Const Function Operator & (y As String) As String Return This + y End Function Const Function Operator == (y As String) As Boolean Return Compare(This, y) = 0 End Function Const Function Operator == (y As *Char) As Boolean Return Compare(This, y) = 0 End Function Const Function Operator <> (y As String) As Boolean Return Compare(This, y) <> 0 End Function Const Function Operator <> (y As *Char) As Boolean Return Compare(This, y) <> 0 End Function Const Function Operator < (y As String) As Boolean Return Compare(This, y) < 0 End Function Const Function Operator < (y As *Char) As Boolean Return Compare(This, y) < 0 End Function Const Function Operator > (y As String) As Boolean Return Compare(This, y) > 0 End Function Const Function Operator > (y As *Char) As Boolean Return Compare(This, y) > 0 End Function Const Function Operator <= (y As String) As Boolean Return Compare(This, y) <= 0 End Function Const Function Operator <= (y As *Char) As Boolean Return Compare(This, y) <= 0 End Function Const Function Operator >= (y As String) As Boolean Return Compare(This, y) >= 0 End Function Const Function Operator >= (y As *Char) As Boolean Return Compare(This, y) >= 0 End Function Static Function Compare(x As String, y As String) As Long Return CompareOrdinal(x, y) End Function Public 'Compareなどで、x.Charsではなく、StrPtr(x)と書く理由は、xがNothingの場合のため。 Static Function Compare(x As String, indexX As Long, y As String, indexY As Long, length As Long) As Long Return CompareOrdinal(x, indexX, y, indexY, length) End Function Static Function CompareOrdinal(x As String, y As String) As Long Return CompareOrdinal(StrPtr(x), StrPtr(y)) End Function Static Function CompareOrdinal(x As String, indexX As Long, y As String, indexY As Long, length As Long) As Long Return CompareOrdinal(StrPtr(x), indexX, StrPtr(y), indexY, length) End Function Private Static Function Compare(x As String, y As *Char) As Long Return CompareOrdinal(x, y) End Function Static Function CompareOrdinal(x As String, y As *Char) As Long Return CompareOrdinal(StrPtr(x), y) End Function Static Function CompareOrdinal(x As *Char, y As *Char) As Long If x = 0 Then If y = 0 Then Return 0 Else Return -1 End If ElseIf y = 0 Then Return 1 End If Return ActiveBasic.Strings.StrCmp(x, y) End Function Static Function CompareOrdinal(x As *Char, indexX As Long, y As *Char, indexY As Long, length As Long) As Long If x = 0 Then If y = 0 Then Return 0 Else Return -1 End If ElseIf y = 0 Then Return 1 End If Return ActiveBasic.Strings.ChrCmp(VarPtr(x[indexX]), VarPtr(y[indexY]), length As SIZE_T) End Function Public Function CompareTo(y As String) As Long Return String.Compare(This, y) End Function Function CompareTo(y As Object) As Long If Not Object.Equals(This.GetType(), y.GetType()) Then Throw New ArgumentException("String.CompareTo: The type of the argument y is not String.", "y") End If Return CompareTo(y As String) End Function Function Equals(s As String) As Boolean Return This = s End Function Override Function Equals(s As Object) As Boolean If Not ActiveBasic.IsNothing(s) Then If Object.Equals(This.GetType(), s.GetType()) Then Return This.Equals(s As String) End If End If Return False End Function Const Function StrPtr() As *Char Return Chars End Function Private Sub Assign(text As PCSTR, textLengthA As Long) #ifdef UNICODE Dim textLengthW = MultiByteToWideChar(CP_THREAD_ACP, 0, text, textLengthA, 0, 0) If AllocStringBuffer(textLengthW) <> 0 Then MultiByteToWideChar(CP_THREAD_ACP, 0, text, textLengthA, Chars, textLengthW) Chars[textLengthW] = 0 End If #else AssignFromCharPtr(text, textLengthA) #endif End Sub Sub Assign(text As PCWSTR, textLengthW As Long) #ifdef UNICODE AssignFromCharPtr(text, textLengthW) #else Dim textLengthA = WideCharToMultiByte(CP_THREAD_ACP, 0, text, textLengthW, 0, 0, 0, 0) If AllocStringBuffer(textLengthA) <> 0 Then WideCharToMultiByte(CP_THREAD_ACP, 0, text, textLengthW, Chars, textLengthA, 0, 0) Chars[textLengthA] = 0 End If #endif End Sub Private Static Function ConcatChar(text1 As *Char, text1Length As Long, text2 As *Char, text2Length As Long) As String ConcatChar = New String() With ConcatChar .AllocStringBuffer(text1Length + text2Length) ActiveBasic.Strings.ChrCopy(.Chars, text1, text1Length As SIZE_T) ActiveBasic.Strings.ChrCopy(VarPtr(.Chars[text1Length]), text2, text2Length As SIZE_T) .Chars[text1Length + text2Length] = 0 End With End Function Public Const Function Concat(text As PCSTR, len As Long) As String #ifdef UNICODE With Concat Dim lenW = MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, 0, 0) Concat = New String .AllocStringBuffer(m_Length + lenW) ActiveBasic.Strings.ChrCopy(.Chars, This.Chars, m_Length As SIZE_T) MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, VarPtr(.Chars[m_Length]), lenW) .Chars[m_Length + lenW] = 0 End With #else Return ConcatChar(This.Chars, m_Length, text, len) #endif End Function Const Function Concat(text As PCWSTR, len As Long) As String #ifdef UNICODE Return ConcatChar(This.Chars, m_Length, text, len) #else With Concat Concat = New String Dim lenA = WideCharToMultiByte(CP_THREAD_ACP, 0, text, len, 0, 0, 0, 0) .AllocStringBuffer(m_Length + lenA) ActiveBasic.Strings.ChrCopy(.Chars, This.Chars, m_Length As SIZE_T) WideCharToMultiByte(CP_THREAD_ACP, 0, text, len, VarPtr(.Chars[m_Length]), lenA, 0, 0) .Chars[m_Length + lenA] = 0 End With #endif End Function Static Function Concat(x As String, y As String) As String If String.IsNullOrEmpty(x) Then Return y Else Return x.Concat(y.Chars, y.m_Length) End If End Function Static Function Concat(x As String, y As String, z As String) As String Dim sb = New Text.StringBuilder(removeNull(x).Length + removeNull(y).Length + removeNull(z).Length) sb.Append(x).Append(y).Append(z) Concat = sb.ToString End Function Static Function Concat(x As String, y As String, z As String, w As String) As String Dim sb = New Text.StringBuilder(removeNull(x).Length + removeNull(y).Length + removeNull(z).Length + removeNull(w).Length) sb.Append(x).Append(y).Append(z).Append(w) Concat = sb.ToString End Function Static Function Concat(x As Object, y As Object) As String Return Concat(x.ToString, y.ToString) End Function Static Function Concat(x As Object, y As Object, z As Object) As String Return Concat(x.ToString, y.ToString, z.ToString) End Function Static Function Concat(x As Object, y As Object, z As Object, w As Object) As String Return Concat(x.ToString, y.ToString, z.ToString, w.ToString) End Function Const Function Contains(c As Char) As Boolean Return IndexOf(c) >= 0 End Function Const Function Contains(s As String) As Boolean If Object.ReferenceEquals(s, Nothing) Then Throw New ArgumentNullException("String.Contains: An argument is null value.", "s") ElseIf s = "" Then Return True Else Return IndexOf(s, 0, m_Length) >= 0 End If End Function Const Function IndexOf(c As Char) As Long Return indexOfCore(c, 0, m_Length) End Function Const Function IndexOf(c As Char, start As Long) As Long rangeCheck(start) Return indexOfCore(c, start, m_Length - start) End Function Const Function IndexOf(c As Char, start As Long, count As Long) As Long rangeCheck(start, count) Return indexOfCore(c, start, count) End Function Private Const Function indexOfCore(c As Char, start As Long, count As Long) As Long indexOfCore = ActiveBasic.Strings.ChrFind(VarPtr(Chars[start]), count, c) As Long If indexOfCore <> -1 Then indexOfCore += start End If End Function Public Const Function IndexOf(s As String) As Long Return IndexOf(s, 0, m_Length) End Function Const Function IndexOf(s As String, startIndex As Long) As Long Return IndexOf(s, startIndex, m_Length - startIndex) End Function Const Function IndexOf(s As String, startIndex As Long, count As Long) As Long rangeCheck(startIndex, count) If Object.ReferenceEquals(s, Nothing) Then Throw New ArgumentNullException("String.IndexOf: An argument is out of range value.", "s") End If Dim length = s.Length If length = 0 Then Return startIndex Dim i As Long, j As Long For i = startIndex To startIndex + count - 1 For j = 0 To length - 1 If Chars[i + j] = s[j] Then If j = length - 1 Then Return i Else Exit For End If Next Next Return -1 End Function Const Function LastIndexOf(c As Char) As Long Return lastIndexOf(c, m_Length - 1, m_Length) End Function Const Function LastIndexOf(c As Char, start As Long) As Long rangeCheck(start) Return lastIndexOf(c, start, start + 1) End Function Const Function LastIndexOf(c As Char, start As Long, count As Long) As Long rangeCheck(start) Dim lastFindPos = start - (count - 1) If Not (m_Length > lastFindPos And lastFindPos >= 0) Then Throw New ArgumentOutOfRangeException("String.LastIndexOf: An argument is out of range value.", "count") End If Return lastIndexOf(c, start, count) End Function Private Const Function lastIndexOf(c As Char, start As Long, count As Long) As Long Dim lastFindPos = start - (count - 1) Dim i As Long For i = start To lastFindPos Step -1 If Chars[i] = c Then Return i End If Next Return -1 End Function Public Const Function LastIndexOf(s As String) As Long Return LastIndexOf(s, m_Length - 1, m_Length) End Function Const Function LastIndexOf(s As String, startIndex As Long) As Long Return LastIndexOf(s, startIndex, startIndex + 1) End Function Const Function LastIndexOf(s As String, start As Long, count As Long) As Long If Object.ReferenceEquals(s, Nothing) Then Throw New ArgumentNullException("String.LastIndexOf: An argument is out of range value.", "s") End If If start < 0 Or start > m_Length - 1 Or _ count < 0 Or count > start + 2 Then Throw New ArgumentOutOfRangeException("String.LastIndexOf: One or more arguments are out of range value.", "start or count or both") End If Dim length = s.m_Length If length > m_Length Then Return -1 If length = 0 Then Return start Dim i As Long, j As Long For i = start To start - count + 1 Step -1 For j = length - 1 To 0 Step -1 If Chars[i + j] = s[j] Then If j = 0 Then Return i Else Exit For End If Next Next Return -1 End Function Const Function StartsWith(c As Char) As Boolean Return IndexOf(c) = 0 End Function Const Function StartsWith(s As String) As Boolean Return IndexOf(s) = 0 End Function Const Function EndsWith(c As Char) As Boolean Return LastIndexOf(c) = m_Length - 1 End Function Const Function EndsWith(s As String) As Boolean Return LastIndexOf(s) = m_Length - s.Length End Function Const Function Insert(startIndex As Long, text As String) As String Dim sb = New Text.StringBuilder(This) sb.Insert(startIndex, text) Return sb.ToString End Function Const Function Substring(startIndex As Long) As String rangeCheck(startIndex) Return Substring(startIndex, m_Length - startIndex) End Function Const Function Substring(startIndex As Long, length As Long) As String rangeCheck(startIndex, length) Return New String(Chars, startIndex, length) End Function Const Function Remove(startIndex As Long) As String rangeCheck(startIndex) Remove = Substring(0, startIndex) End Function Const Function Remove(startIndex As Long, count As Long) As String Dim sb = New Text.StringBuilder(This) sb.Remove(startIndex, count) Remove = sb.ToString End Function Static Function IsNullOrEmpty(s As String) As Boolean If Not Object.ReferenceEquals(s, Nothing) Then If s.m_Length > 0 Then Return False End If End If Return True End Function Const Function Replace(oldChar As Char, newChar As Char) As String Dim sb = New Text.StringBuilder(This) sb.Replace(oldChar, newChar) Replace = sb.ToString End Function Const Function Replace(oldStr As String, newStr As String) As String Dim sb = New Text.StringBuilder(This) sb.Replace(oldStr, newStr) Return sb.ToString End Function Function Split(separator As System.Collections.Generic.List) As System.Collections.Generic.List Return Split(separator, -1, StringSplitOptions.None) End Function Function Split(separator As System.Collections.Generic.List, options As StringSplitOptions) As System.Collections.Generic.List Return Split(separator, -1, options) End Function Function Split(separator As System.Collections.Generic.List, count As Long, options As StringSplitOptions) As System.Collections.Generic.List Dim split As System.Collections.Generic.List Dim index As Long, t1Index As Long, t2Index As Long Dim s As String, substring As String Dim flag As Boolean Do t1Index = Length flag = True Foreach s In separator t2Index = IndexOf(s, index) If t2Index > -1 Then t1Index = Math.Min(t1Index, t2Index) flag = False End If Next substring = Substring(index, t1Index - index) If Not ( IsNullOrEmpty(substring) and (options = StringSplitOptions.RemoveEmptyEntries) ) Then split.Add(substring) End If If flag Then Return split If split.Count = count Then Return split index = t1Index + 1 Loop End Function Static Function Join(separator As String, strings As System.Collections.Generic.List) As String Return Join(separator, strings, 0, strings.Count) End Function Static Function Join(separator As String, strings As System.Collections.Generic.List, startIndex As Long, count As Long) As String If (startIndex+count > strings.Count) or (startIndex < 0) or (count < 1) Then Throw New ArgumentOutOfRangeException("String.Join: One or more arguments are out of range value.", "startIndex or count") End If Dim string As String Dim i As Long For i = startIndex To startIndex + count - 2 string += strings[i] + separator Next Return string + strings[i] End Function Const Function ToLower() As String Dim sb = New Text.StringBuilder(m_Length) sb.Length = m_Length Dim i As Long For i = 0 To ELM(m_Length) sb[i] = ActiveBasic.CType.ToLower(Chars[i]) Next Return sb.ToString End Function Const Function ToUpper() As String Dim sb = New Text.StringBuilder(m_Length) sb.Length = m_Length Dim i As Long For i = 0 To ELM(m_Length) sb[i] = ActiveBasic.CType.ToUpper(Chars[i]) Next Return sb.ToString End Function Override Function ToString() As String ToString = This End Function Const Function Clone() As String Clone = This End Function /* Function Clone() As Object Clone = This End Function */ Static Function Copy(s As String) As String Copy = New String(s.Chars, s.m_Length) End Function Sub CopyTo(sourceIndex As Long, destination As *Char, destinationIndex As Long, count As Long) ActiveBasic.Strings.ChrCopy(VarPtr(destination[destinationIndex]), VarPtr(Chars[sourceIndex]), count As SIZE_T) End Sub Override Function GetHashCode() As Long #ifdef UNICODE Dim size = m_Length #else Dim size = (m_Length + 1) >> 1 #endif Return _System_GetHashFromWordArray(Chars As *Word, size) Xor m_Length End Function Function PadLeft(total As Long) As String PadLeft(total, &h30 As Char) End Function Function PadLeft(total As Long, c As Char) As String If total < 0 Then Throw New ArgumentOutOfRangeException("String.PadLeft: An arguments is out of range value.", "total") End If If total >= m_Length Then Return This End If Dim sb = New Text.StringBuilder(total) sb.Append(c, total - m_Length) sb.Append(This) Return sb.ToString End Function Function PadRight(total As Long) As String PadRight(total, &h30 As Char) End Function Function PadRight(total As Long, c As Char) As String If total < 0 Then Throw New ArgumentOutOfRangeException("String.PadRight: An arguments is out of range value.", "total") End If If total >= m_Length Then Return This End If Dim sb = New Text.StringBuilder(total) sb.Append(This) sb.Append(c, total - m_Length) Return sb.ToString End Function Private Function AllocStringBuffer(textLength As Long) As *Char If textLength < 0 Then Return 0 End If AllocStringBuffer = GC_malloc_atomic(SizeOf(Char) * (textLength + 1)) If AllocStringBuffer = 0 Then 'Throw New OutOfMemoryException End If m_Length = textLength Chars = AllocStringBuffer End Function Sub AssignFromCharPtr(text As *Char, textLength As Long) AllocStringBuffer(textLength) ActiveBasic.Strings.ChrCopy(Chars, text, textLength As SIZE_T) Chars[m_Length] = 0 End Sub Const Sub rangeCheck(index As Long) If index < 0 Or index > m_Length Then Throw New ArgumentOutOfRangeException("String: An arguments is out of range value.", "index") End If End Sub Const Sub rangeCheck(start As Long, length As Long) If start < 0 Or start > This.m_Length Or length < 0 Then Throw New ArgumentOutOfRangeException("String: One or more arguments are out of range value.", "start or length or both") End If End Sub Static Function removeNull(s As String) As String If ActiveBasic.IsNothing(s) Then removeNull = Empty Else removeNull = s End If End Function End Class Enum StringSplitOptions None RemoveEmptyEntries End Enum End Namespace