2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../core/juce_StandardHeader.h"
29 #pragma warning (push)
30 #pragma warning (disable: 4514 4996)
37 #include "juce_String.h"
38 #include "../memory/juce_Atomic.h"
39 #include "../memory/juce_HeapBlock.h"
40 #include "../io/streams/juce_OutputStream.h"
44 #if defined (JUCE_STRINGS_ARE_UNICODE) && ! JUCE_STRINGS_ARE_UNICODE
45 #error "JUCE_STRINGS_ARE_UNICODE is deprecated! All strings are now unicode by default."
48 #if JUCE_NATIVE_WCHAR_IS_UTF8
49 typedef CharPointer_UTF8 CharPointer_wchar_t
;
50 #elif JUCE_NATIVE_WCHAR_IS_UTF16
51 typedef CharPointer_UTF16 CharPointer_wchar_t
;
53 typedef CharPointer_UTF32 CharPointer_wchar_t
;
56 static inline CharPointer_wchar_t
castToCharPointer_wchar_t (const void* t
) noexcept
58 return CharPointer_wchar_t (static_cast <const CharPointer_wchar_t::CharType
*> (t
));
61 //==============================================================================
66 : refCount (0x3fffffff), allocatedNumBytes (sizeof (*text
))
71 typedef String::CharPointerType CharPointerType
;
72 typedef String::CharPointerType::CharType CharType
;
74 //==============================================================================
75 static const CharPointerType
createUninitialisedBytes (const size_t numBytes
)
77 StringHolder
* const s
= reinterpret_cast <StringHolder
*> (new char [sizeof (StringHolder
) - sizeof (CharType
) + numBytes
]);
78 s
->refCount
.value
= 0;
79 s
->allocatedNumBytes
= numBytes
;
80 return CharPointerType (s
->text
);
83 template <class CharPointer
>
84 static const CharPointerType
createFromCharPointer (const CharPointer
& text
)
86 if (text
.getAddress() == nullptr || text
.isEmpty())
90 size_t bytesNeeded
= sizeof (CharType
);
93 bytesNeeded
+= CharPointerType::getBytesRequiredFor (t
.getAndAdvance());
95 const CharPointerType
dest (createUninitialisedBytes (bytesNeeded
));
96 CharPointerType (dest
).writeAll (text
);
100 template <class CharPointer
>
101 static const CharPointerType
createFromCharPointer (const CharPointer
& text
, size_t maxChars
)
103 if (text
.getAddress() == nullptr || text
.isEmpty() || maxChars
== 0)
106 CharPointer
end (text
);
108 size_t bytesNeeded
= sizeof (CharType
);
110 while (numChars
< maxChars
&& ! end
.isEmpty())
112 bytesNeeded
+= CharPointerType::getBytesRequiredFor (end
.getAndAdvance());
116 const CharPointerType
dest (createUninitialisedBytes (bytesNeeded
));
117 CharPointerType (dest
).writeWithCharLimit (text
, (int) numChars
+ 1);
121 template <class CharPointer
>
122 static const CharPointerType
createFromCharPointer (const CharPointer
& start
, const CharPointer
& end
)
124 if (start
.getAddress() == nullptr || start
.isEmpty())
127 CharPointer
e (start
);
129 size_t bytesNeeded
= sizeof (CharType
);
131 while (e
< end
&& ! e
.isEmpty())
133 bytesNeeded
+= CharPointerType::getBytesRequiredFor (e
.getAndAdvance());
137 const CharPointerType
dest (createUninitialisedBytes (bytesNeeded
));
138 CharPointerType (dest
).writeWithCharLimit (start
, numChars
+ 1);
142 static const CharPointerType
createFromFixedLength (const char* const src
, const size_t numChars
)
144 const CharPointerType
dest (createUninitialisedBytes (numChars
* sizeof (CharType
) + sizeof (CharType
)));
145 CharPointerType (dest
).writeWithCharLimit (CharPointer_UTF8 (src
), (int) (numChars
+ 1));
149 static inline const CharPointerType
getEmpty() noexcept
151 return CharPointerType (empty
.text
);
154 //==============================================================================
155 static void retain (const CharPointerType
& text
) noexcept
157 ++(bufferFromText (text
)->refCount
);
160 static inline void release (StringHolder
* const b
) noexcept
162 if (--(b
->refCount
) == -1 && b
!= &empty
)
163 delete[] reinterpret_cast <char*> (b
);
166 static void release (const CharPointerType
& text
) noexcept
168 release (bufferFromText (text
));
171 //==============================================================================
172 static CharPointerType
makeUnique (const CharPointerType
& text
)
174 StringHolder
* const b
= bufferFromText (text
);
176 if (b
->refCount
.get() <= 0)
179 CharPointerType
newText (createUninitialisedBytes (b
->allocatedNumBytes
));
180 memcpy (newText
.getAddress(), text
.getAddress(), b
->allocatedNumBytes
);
186 static CharPointerType
makeUniqueWithByteSize (const CharPointerType
& text
, size_t numBytes
)
188 StringHolder
* const b
= bufferFromText (text
);
190 if (b
->refCount
.get() <= 0 && b
->allocatedNumBytes
>= numBytes
)
193 CharPointerType
newText (createUninitialisedBytes (jmax (b
->allocatedNumBytes
, numBytes
)));
194 memcpy (newText
.getAddress(), text
.getAddress(), b
->allocatedNumBytes
);
200 static size_t getAllocatedNumBytes (const CharPointerType
& text
) noexcept
202 return bufferFromText (text
)->allocatedNumBytes
;
205 //==============================================================================
206 Atomic
<int> refCount
;
207 size_t allocatedNumBytes
;
210 static StringHolder empty
;
213 static inline StringHolder
* bufferFromText (const CharPointerType
& text
) noexcept
215 // (Can't use offsetof() here because of warnings about this not being a POD)
216 return reinterpret_cast <StringHolder
*> (reinterpret_cast <char*> (text
.getAddress())
217 - (reinterpret_cast <size_t> (reinterpret_cast <StringHolder
*> (1)->text
) - 1));
220 void compileTimeChecks()
222 // Let me know if any of these assertions fail on your system!
223 #if JUCE_NATIVE_WCHAR_IS_UTF8
224 static_jassert (sizeof (wchar_t) == 1);
225 #elif JUCE_NATIVE_WCHAR_IS_UTF16
226 static_jassert (sizeof (wchar_t) == 2);
227 #elif JUCE_NATIVE_WCHAR_IS_UTF32
228 static_jassert (sizeof (wchar_t) == 4);
230 #error "native wchar_t size is unknown"
235 StringHolder
StringHolder::empty
;
236 const String
String::empty
;
238 //==============================================================================
239 void String::preallocateBytes (const size_t numBytesNeeded
)
241 text
= StringHolder::makeUniqueWithByteSize (text
, numBytesNeeded
+ sizeof (CharPointerType::CharType
));
244 //==============================================================================
245 String::String() noexcept
246 : text (StringHolder::getEmpty())
250 String::~String() noexcept
252 StringHolder::release (text
);
255 String::String (const String
& other
) noexcept
258 StringHolder::retain (text
);
261 void String::swapWith (String
& other
) noexcept
263 std::swap (text
, other
.text
);
266 String
& String::operator= (const String
& other
) noexcept
268 StringHolder::retain (other
.text
);
269 StringHolder::release (text
.atomicSwap (other
.text
));
273 inline String::PreallocationBytes::PreallocationBytes (const size_t numBytes_
) : numBytes (numBytes_
) {}
275 String::String (const PreallocationBytes
& preallocationSize
)
276 : text (StringHolder::createUninitialisedBytes (preallocationSize
.numBytes
+ sizeof (CharPointerType::CharType
)))
280 //==============================================================================
281 String::String (const char* const t
)
282 : text (StringHolder::createFromCharPointer (CharPointer_ASCII (t
)))
284 /* If you get an assertion here, then you're trying to create a string from 8-bit data
285 that contains values greater than 127. These can NOT be correctly converted to unicode
286 because there's no way for the String class to know what encoding was used to
287 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
289 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
290 string to the String class - so for example if your source data is actually UTF-8,
291 you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
292 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
293 you use UTF-8 with escape characters in your source code to represent extended characters,
294 because there's no other way to represent these strings in a way that isn't dependent on
295 the compiler, source code editor and platform.
297 jassert (t
== nullptr || CharPointer_ASCII::isValidString (t
, std::numeric_limits
<int>::max()));
300 String::String (const char* const t
, const size_t maxChars
)
301 : text (StringHolder::createFromCharPointer (CharPointer_ASCII (t
), maxChars
))
303 /* If you get an assertion here, then you're trying to create a string from 8-bit data
304 that contains values greater than 127. These can NOT be correctly converted to unicode
305 because there's no way for the String class to know what encoding was used to
306 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
308 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
309 string to the String class - so for example if your source data is actually UTF-8,
310 you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
311 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
312 you use UTF-8 with escape characters in your source code to represent extended characters,
313 because there's no other way to represent these strings in a way that isn't dependent on
314 the compiler, source code editor and platform.
316 jassert (t
== nullptr || CharPointer_ASCII::isValidString (t
, (int) maxChars
));
319 String::String (const wchar_t* const t
) : text (StringHolder::createFromCharPointer (castToCharPointer_wchar_t (t
))) {}
320 String::String (const CharPointer_UTF8
& t
) : text (StringHolder::createFromCharPointer (t
)) {}
321 String::String (const CharPointer_UTF16
& t
) : text (StringHolder::createFromCharPointer (t
)) {}
322 String::String (const CharPointer_UTF32
& t
) : text (StringHolder::createFromCharPointer (t
)) {}
323 String::String (const CharPointer_ASCII
& t
) : text (StringHolder::createFromCharPointer (t
)) {}
325 String::String (const CharPointer_UTF8
& t
, const size_t maxChars
) : text (StringHolder::createFromCharPointer (t
, maxChars
)) {}
326 String::String (const CharPointer_UTF16
& t
, const size_t maxChars
) : text (StringHolder::createFromCharPointer (t
, maxChars
)) {}
327 String::String (const CharPointer_UTF32
& t
, const size_t maxChars
) : text (StringHolder::createFromCharPointer (t
, maxChars
)) {}
328 String::String (const wchar_t* const t
, size_t maxChars
) : text (StringHolder::createFromCharPointer (castToCharPointer_wchar_t (t
), maxChars
)) {}
330 String::String (const CharPointer_UTF8
& start
, const CharPointer_UTF8
& end
) : text (StringHolder::createFromCharPointer (start
, end
)) {}
331 String::String (const CharPointer_UTF16
& start
, const CharPointer_UTF16
& end
) : text (StringHolder::createFromCharPointer (start
, end
)) {}
332 String::String (const CharPointer_UTF32
& start
, const CharPointer_UTF32
& end
) : text (StringHolder::createFromCharPointer (start
, end
)) {}
334 String
String::charToString (const juce_wchar character
)
336 String
result (PreallocationBytes (CharPointerType::getBytesRequiredFor (character
)));
337 CharPointerType
t (result
.text
);
343 //==============================================================================
344 namespace NumberToStringConverters
346 // pass in a pointer to the END of a buffer..
347 char* numberToString (char* t
, const int64 n
) noexcept
350 int64 v
= (n
>= 0) ? n
: -n
;
354 *--t
= (char) ('0' + (int) (v
% 10));
365 char* numberToString (char* t
, uint64 v
) noexcept
371 *--t
= (char) ('0' + (int) (v
% 10));
379 char* numberToString (char* t
, const int n
) noexcept
381 if (n
== (int) 0x80000000) // (would cause an overflow)
382 return numberToString (t
, (int64
) n
);
389 *--t
= (char) ('0' + (v
% 10));
400 char* numberToString (char* t
, unsigned int v
) noexcept
406 *--t
= (char) ('0' + (v
% 10));
414 char getDecimalPoint()
416 static char dp
= (char)
417 #if JUCE_VC7_OR_EARLIER
418 std::_USE (std::locale(), std::numpunct
<char>).decimal_point();
420 std::use_facet
<std::numpunct
<char> > (std::locale()).decimal_point();
426 char* doubleToString (char* buffer
, int numChars
, double n
, int numDecPlaces
, size_t& len
) noexcept
428 if (numDecPlaces
> 0 && n
> -1.0e20
&& n
< 1.0e20
)
430 char* const end
= buffer
+ numChars
;
432 int64 v
= (int64
) (pow (10.0, numDecPlaces
) * std::abs (n
) + 0.5);
435 while (numDecPlaces
>= 0 || v
> 0)
437 if (numDecPlaces
== 0)
438 *--t
= (char) getDecimalPoint();
440 *--t
= (char) ('0' + (v
% 10));
454 len
= sprintf (buffer
, "%.9g", n
);
459 template <typename IntegerType
>
460 const String::CharPointerType
createFromInteger (const IntegerType number
)
463 char* const end
= buffer
+ numElementsInArray (buffer
);
464 char* const start
= numberToString (end
, number
);
466 return StringHolder::createFromFixedLength (start
, end
- start
- 1);
469 const String::CharPointerType
createFromDouble (const double number
, const int numberOfDecimalPlaces
)
473 char* const start
= doubleToString (buffer
, numElementsInArray (buffer
), (double) number
, numberOfDecimalPlaces
, len
);
474 return StringHolder::createFromFixedLength (start
, len
);
478 //==============================================================================
479 String::String (const int number
) : text (NumberToStringConverters::createFromInteger (number
)) {}
480 String::String (const unsigned int number
) : text (NumberToStringConverters::createFromInteger (number
)) {}
481 String::String (const short number
) : text (NumberToStringConverters::createFromInteger ((int) number
)) {}
482 String::String (const unsigned short number
) : text (NumberToStringConverters::createFromInteger ((unsigned int) number
)) {}
483 String::String (const int64 number
) : text (NumberToStringConverters::createFromInteger (number
)) {}
484 String::String (const uint64 number
) : text (NumberToStringConverters::createFromInteger (number
)) {}
486 String::String (const float number
, const int numberOfDecimalPlaces
) : text (NumberToStringConverters::createFromDouble ((double) number
, numberOfDecimalPlaces
)) {}
487 String::String (const double number
, const int numberOfDecimalPlaces
) : text (NumberToStringConverters::createFromDouble (number
, numberOfDecimalPlaces
)) {}
489 //==============================================================================
490 int String::length() const noexcept
492 return (int) text
.length();
495 size_t String::getByteOffsetOfEnd() const noexcept
497 return ((char*) text
.findTerminatingNull().getAddress()) - (char*) text
.getAddress();
500 const juce_wchar
String::operator[] (int index
) const noexcept
502 jassert (index
== 0 || (index
> 0 && index
<= (int) text
.lengthUpTo (index
+ 1)));
506 int String::hashCode() const noexcept
508 CharPointerType
t (text
);
511 while (! t
.isEmpty())
512 result
= 31 * result
+ t
.getAndAdvance();
517 int64
String::hashCode64() const noexcept
519 CharPointerType
t (text
);
522 while (! t
.isEmpty())
523 result
= 101 * result
+ t
.getAndAdvance();
528 //==============================================================================
529 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const String
& s2
) noexcept
{ return s1
.compare (s2
) == 0; }
530 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const char* const s2
) noexcept
{ return s1
.compare (s2
) == 0; }
531 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const wchar_t* const s2
) noexcept
{ return s1
.compare (s2
) == 0; }
532 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const CharPointer_UTF8
& s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) == 0; }
533 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const CharPointer_UTF16
& s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) == 0; }
534 JUCE_API
bool JUCE_CALLTYPE
operator== (const String
& s1
, const CharPointer_UTF32
& s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) == 0; }
535 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const String
& s2
) noexcept
{ return s1
.compare (s2
) != 0; }
536 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const char* const s2
) noexcept
{ return s1
.compare (s2
) != 0; }
537 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const wchar_t* const s2
) noexcept
{ return s1
.compare (s2
) != 0; }
538 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const CharPointer_UTF8
& s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) != 0; }
539 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const CharPointer_UTF16
& s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) != 0; }
540 JUCE_API
bool JUCE_CALLTYPE
operator!= (const String
& s1
, const CharPointer_UTF32
& s2
) noexcept
{ return s1
.getCharPointer().compare (s2
) != 0; }
541 JUCE_API
bool JUCE_CALLTYPE
operator> (const String
& s1
, const String
& s2
) noexcept
{ return s1
.compare (s2
) > 0; }
542 JUCE_API
bool JUCE_CALLTYPE
operator< (const String
& s1
, const String
& s2
) noexcept
{ return s1
.compare (s2
) < 0; }
543 JUCE_API
bool JUCE_CALLTYPE
operator>= (const String
& s1
, const String
& s2
) noexcept
{ return s1
.compare (s2
) >= 0; }
544 JUCE_API
bool JUCE_CALLTYPE
operator<= (const String
& s1
, const String
& s2
) noexcept
{ return s1
.compare (s2
) <= 0; }
546 bool String::equalsIgnoreCase (const wchar_t* const t
) const noexcept
548 return t
!= nullptr ? text
.compareIgnoreCase (castToCharPointer_wchar_t (t
)) == 0
552 bool String::equalsIgnoreCase (const char* const t
) const noexcept
554 return t
!= nullptr ? text
.compareIgnoreCase (CharPointer_UTF8 (t
)) == 0
558 bool String::equalsIgnoreCase (const String
& other
) const noexcept
560 return text
== other
.text
561 || text
.compareIgnoreCase (other
.text
) == 0;
564 int String::compare (const String
& other
) const noexcept
{ return (text
== other
.text
) ? 0 : text
.compare (other
.text
); }
565 int String::compare (const char* const other
) const noexcept
{ return text
.compare (CharPointer_UTF8 (other
)); }
566 int String::compare (const wchar_t* const other
) const noexcept
{ return text
.compare (castToCharPointer_wchar_t (other
)); }
567 int String::compareIgnoreCase (const String
& other
) const noexcept
{ return (text
== other
.text
) ? 0 : text
.compareIgnoreCase (other
.text
); }
569 int String::compareLexicographically (const String
& other
) const noexcept
571 CharPointerType
s1 (text
);
573 while (! (s1
.isEmpty() || s1
.isLetterOrDigit()))
576 CharPointerType
s2 (other
.text
);
578 while (! (s2
.isEmpty() || s2
.isLetterOrDigit()))
581 return s1
.compareIgnoreCase (s2
);
584 //==============================================================================
585 void String::append (const String
& textToAppend
, size_t maxCharsToTake
)
587 appendCharPointer (textToAppend
.text
, maxCharsToTake
);
590 String
& String::operator+= (const wchar_t* const t
)
592 appendCharPointer (castToCharPointer_wchar_t (t
));
596 String
& String::operator+= (const char* const t
)
598 /* If you get an assertion here, then you're trying to create a string from 8-bit data
599 that contains values greater than 127. These can NOT be correctly converted to unicode
600 because there's no way for the String class to know what encoding was used to
601 create them. The source data could be UTF-8, ASCII or one of many local code-pages.
603 To get around this problem, you must be more explicit when you pass an ambiguous 8-bit
604 string to the String class - so for example if your source data is actually UTF-8,
605 you'd call String (CharPointer_UTF8 ("my utf8 string..")), and it would be able to
606 correctly convert the multi-byte characters to unicode. It's *highly* recommended that
607 you use UTF-8 with escape characters in your source code to represent extended characters,
608 because there's no other way to represent these strings in a way that isn't dependent on
609 the compiler, source code editor and platform.
611 jassert (t
== nullptr || CharPointer_ASCII::isValidString (t
, std::numeric_limits
<int>::max()));
613 appendCharPointer (CharPointer_ASCII (t
));
617 String
& String::operator+= (const String
& other
)
620 return operator= (other
);
622 appendCharPointer (other
.text
);
626 String
& String::operator+= (const char ch
)
628 const char asString
[] = { ch
, 0 };
629 return operator+= (asString
);
632 String
& String::operator+= (const wchar_t ch
)
634 const wchar_t asString
[] = { ch
, 0 };
635 return operator+= (asString
);
638 #if ! JUCE_NATIVE_WCHAR_IS_UTF32
639 String
& String::operator+= (const juce_wchar ch
)
641 const juce_wchar asString
[] = { ch
, 0 };
642 appendCharPointer (CharPointer_UTF32 (asString
));
647 String
& String::operator+= (const int number
)
650 char* const end
= buffer
+ numElementsInArray (buffer
);
651 char* const start
= NumberToStringConverters::numberToString (end
, number
);
653 const int numExtraChars
= (int) (end
- start
);
655 if (numExtraChars
> 0)
657 const size_t byteOffsetOfNull
= getByteOffsetOfEnd();
658 const size_t newBytesNeeded
= sizeof (CharPointerType::CharType
) + byteOffsetOfNull
659 + sizeof (CharPointerType::CharType
) * numExtraChars
;
661 text
= StringHolder::makeUniqueWithByteSize (text
, newBytesNeeded
);
663 CharPointerType
newEnd (addBytesToPointer (text
.getAddress(), (int) byteOffsetOfNull
));
664 newEnd
.writeWithCharLimit (CharPointer_ASCII (start
), numExtraChars
);
670 //==============================================================================
671 JUCE_API String JUCE_CALLTYPE
operator+ (const char* const string1
, const String
& string2
)
677 JUCE_API String JUCE_CALLTYPE
operator+ (const wchar_t* const string1
, const String
& string2
)
683 JUCE_API String JUCE_CALLTYPE
operator+ (const char s1
, const String
& s2
) { return String::charToString (s1
) + s2
; }
684 JUCE_API String JUCE_CALLTYPE
operator+ (const wchar_t s1
, const String
& s2
) { return String::charToString (s1
) + s2
; }
685 #if ! JUCE_NATIVE_WCHAR_IS_UTF32
686 JUCE_API String JUCE_CALLTYPE
operator+ (const juce_wchar s1
, const String
& s2
) { return String::charToString (s1
) + s2
; }
689 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, const String
& s2
) { return s1
+= s2
; }
690 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, const char* const s2
) { return s1
+= s2
; }
691 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, const wchar_t* s2
) { return s1
+= s2
; }
693 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, const char s2
) { return s1
+= s2
; }
694 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, const wchar_t s2
) { return s1
+= s2
; }
695 #if ! JUCE_NATIVE_WCHAR_IS_UTF32
696 JUCE_API String JUCE_CALLTYPE
operator+ (String s1
, const juce_wchar s2
) { return s1
+= s2
; }
699 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const char s2
) { return s1
+= s2
; }
700 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const wchar_t s2
) { return s1
+= s2
; }
701 #if ! JUCE_NATIVE_WCHAR_IS_UTF32
702 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const juce_wchar s2
) { return s1
+= s2
; }
705 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const char* const s2
) { return s1
+= s2
; }
706 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const wchar_t* const s2
) { return s1
+= s2
; }
707 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const String
& s2
) { return s1
+= s2
; }
709 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const short number
) { return s1
+= (int) number
; }
710 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const int number
) { return s1
+= number
; }
711 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const long number
) { return s1
+= (int) number
; }
712 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const float number
) { return s1
+= String (number
); }
713 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& s1
, const double number
) { return s1
+= String (number
); }
715 JUCE_API OutputStream
& JUCE_CALLTYPE
operator<< (OutputStream
& stream
, const String
& text
)
717 const int numBytes
= text
.getNumBytesAsUTF8();
719 #if (JUCE_STRING_UTF_TYPE == 8)
720 stream
.write (text
.getCharPointer().getAddress(), numBytes
);
722 // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
723 // if lots of large, persistent strings were to be written to streams).
724 HeapBlock
<char> temp (numBytes
+ 1);
725 CharPointer_UTF8 (temp
).writeAll (text
.getCharPointer());
726 stream
.write (temp
, numBytes
);
732 JUCE_API String
& JUCE_CALLTYPE
operator<< (String
& string1
, const NewLine
&)
734 return string1
+= NewLine::getDefault();
737 //==============================================================================
738 int String::indexOfChar (const juce_wchar character
) const noexcept
740 return text
.indexOf (character
);
743 int String::indexOfChar (const int startIndex
, const juce_wchar character
) const noexcept
745 CharPointerType
t (text
);
747 for (int i
= 0; ! t
.isEmpty(); ++i
)
751 if (t
.getAndAdvance() == character
)
763 int String::lastIndexOfChar (const juce_wchar character
) const noexcept
765 CharPointerType
t (text
);
768 for (int i
= 0; ! t
.isEmpty(); ++i
)
769 if (t
.getAndAdvance() == character
)
775 int String::indexOfAnyOf (const String
& charactersToLookFor
, const int startIndex
, const bool ignoreCase
) const noexcept
777 CharPointerType
t (text
);
779 for (int i
= 0; ! t
.isEmpty(); ++i
)
783 if (charactersToLookFor
.text
.indexOf (t
.getAndAdvance(), ignoreCase
) >= 0)
795 int String::indexOf (const String
& other
) const noexcept
797 return other
.isEmpty() ? 0 : text
.indexOf (other
.text
);
800 int String::indexOfIgnoreCase (const String
& other
) const noexcept
802 return other
.isEmpty() ? 0 : CharacterFunctions::indexOfIgnoreCase (text
, other
.text
);
805 int String::indexOf (const int startIndex
, const String
& other
) const noexcept
810 CharPointerType
t (text
);
812 for (int i
= startIndex
; --i
>= 0;)
820 int found
= t
.indexOf (other
.text
);
826 int String::indexOfIgnoreCase (const int startIndex
, const String
& other
) const noexcept
831 CharPointerType
t (text
);
833 for (int i
= startIndex
; --i
>= 0;)
841 int found
= CharacterFunctions::indexOfIgnoreCase (t
, other
.text
);
847 int String::lastIndexOf (const String
& other
) const noexcept
849 if (other
.isNotEmpty())
851 const int len
= other
.length();
852 int i
= length() - len
;
856 CharPointerType
n (text
+ i
);
860 if (n
.compareUpTo (other
.text
, len
) == 0)
872 int String::lastIndexOfIgnoreCase (const String
& other
) const noexcept
874 if (other
.isNotEmpty())
876 const int len
= other
.length();
877 int i
= length() - len
;
881 CharPointerType
n (text
+ i
);
885 if (n
.compareIgnoreCaseUpTo (other
.text
, len
) == 0)
897 int String::lastIndexOfAnyOf (const String
& charactersToLookFor
, const bool ignoreCase
) const noexcept
899 CharPointerType
t (text
);
902 for (int i
= 0; ! t
.isEmpty(); ++i
)
903 if (charactersToLookFor
.text
.indexOf (t
.getAndAdvance(), ignoreCase
) >= 0)
909 bool String::contains (const String
& other
) const noexcept
911 return indexOf (other
) >= 0;
914 bool String::containsChar (const juce_wchar character
) const noexcept
916 return text
.indexOf (character
) >= 0;
919 bool String::containsIgnoreCase (const String
& t
) const noexcept
921 return indexOfIgnoreCase (t
) >= 0;
924 int String::indexOfWholeWord (const String
& word
) const noexcept
926 if (word
.isNotEmpty())
928 CharPointerType
t (text
);
929 const int wordLen
= word
.length();
930 const int end
= (int) t
.length() - wordLen
;
932 for (int i
= 0; i
<= end
; ++i
)
934 if (t
.compareUpTo (word
.text
, wordLen
) == 0
935 && (i
== 0 || ! (t
- 1).isLetterOrDigit())
936 && ! (t
+ wordLen
).isLetterOrDigit())
946 int String::indexOfWholeWordIgnoreCase (const String
& word
) const noexcept
948 if (word
.isNotEmpty())
950 CharPointerType
t (text
);
951 const int wordLen
= word
.length();
952 const int end
= (int) t
.length() - wordLen
;
954 for (int i
= 0; i
<= end
; ++i
)
956 if (t
.compareIgnoreCaseUpTo (word
.text
, wordLen
) == 0
957 && (i
== 0 || ! (t
- 1).isLetterOrDigit())
958 && ! (t
+ wordLen
).isLetterOrDigit())
968 bool String::containsWholeWord (const String
& wordToLookFor
) const noexcept
970 return indexOfWholeWord (wordToLookFor
) >= 0;
973 bool String::containsWholeWordIgnoreCase (const String
& wordToLookFor
) const noexcept
975 return indexOfWholeWordIgnoreCase (wordToLookFor
) >= 0;
978 //==============================================================================
979 namespace WildCardHelpers
981 int indexOfMatch (const String::CharPointerType
& wildcard
,
982 String::CharPointerType test
,
983 const bool ignoreCase
) noexcept
987 while (! test
.isEmpty())
989 String::CharPointerType
t (test
);
990 String::CharPointerType
w (wildcard
);
994 const juce_wchar wc
= *w
;
995 const juce_wchar tc
= *t
;
998 || (ignoreCase
&& w
.toLowerCase() == t
.toLowerCase())
999 || (wc
== '?' && tc
!= 0))
1009 if (wc
== '*' && (w
[1] == 0 || indexOfMatch (w
+ 1, t
, ignoreCase
) >= 0))
1024 bool String::matchesWildcard (const String
& wildcard
, const bool ignoreCase
) const noexcept
1026 CharPointerType
w (wildcard
.text
);
1027 CharPointerType
t (text
);
1031 const juce_wchar wc
= *w
;
1032 const juce_wchar tc
= *t
;
1035 || (ignoreCase
&& w
.toLowerCase() == t
.toLowerCase())
1036 || (wc
== '?' && tc
!= 0))
1046 return wc
== '*' && (w
[1] == 0 || WildCardHelpers::indexOfMatch (w
+ 1, t
, ignoreCase
) >= 0);
1051 //==============================================================================
1052 String
String::repeatedString (const String
& stringToRepeat
, int numberOfTimesToRepeat
)
1054 if (numberOfTimesToRepeat
<= 0)
1055 return String::empty
;
1057 String
result (PreallocationBytes (stringToRepeat
.getByteOffsetOfEnd() * numberOfTimesToRepeat
));
1058 CharPointerType
n (result
.text
);
1060 while (--numberOfTimesToRepeat
>= 0)
1061 n
.writeAll (stringToRepeat
.text
);
1066 String
String::paddedLeft (const juce_wchar padCharacter
, int minimumLength
) const
1068 jassert (padCharacter
!= 0);
1070 int extraChars
= minimumLength
;
1071 CharPointerType
end (text
);
1073 while (! end
.isEmpty())
1079 if (extraChars
<= 0 || padCharacter
== 0)
1082 const size_t currentByteSize
= ((char*) end
.getAddress()) - (char*) text
.getAddress();
1083 String
result (PreallocationBytes (currentByteSize
+ extraChars
* CharPointerType::getBytesRequiredFor (padCharacter
)));
1084 CharPointerType
n (result
.text
);
1086 while (--extraChars
>= 0)
1087 n
.write (padCharacter
);
1093 String
String::paddedRight (const juce_wchar padCharacter
, int minimumLength
) const
1095 jassert (padCharacter
!= 0);
1097 int extraChars
= minimumLength
;
1098 CharPointerType
end (text
);
1100 while (! end
.isEmpty())
1106 if (extraChars
<= 0 || padCharacter
== 0)
1109 const size_t currentByteSize
= ((char*) end
.getAddress()) - (char*) text
.getAddress();
1110 String
result (PreallocationBytes (currentByteSize
+ extraChars
* CharPointerType::getBytesRequiredFor (padCharacter
)));
1111 CharPointerType
n (result
.text
);
1115 while (--extraChars
>= 0)
1116 n
.write (padCharacter
);
1122 //==============================================================================
1123 String
String::replaceSection (int index
, int numCharsToReplace
, const String
& stringToInsert
) const
1127 // a negative index to replace from?
1132 if (numCharsToReplace
< 0)
1134 // replacing a negative number of characters?
1135 numCharsToReplace
= 0;
1140 CharPointerType
insertPoint (text
);
1144 if (insertPoint
.isEmpty())
1146 // replacing beyond the end of the string?
1148 return *this + stringToInsert
;
1155 CharPointerType
startOfRemainder (insertPoint
);
1158 while (i
< numCharsToReplace
&& ! startOfRemainder
.isEmpty())
1164 if (insertPoint
== text
&& startOfRemainder
.isEmpty())
1165 return stringToInsert
;
1167 const size_t initialBytes
= ((char*) insertPoint
.getAddress()) - (char*) text
.getAddress();
1168 const size_t newStringBytes
= stringToInsert
.getByteOffsetOfEnd();
1169 const size_t remainderBytes
= ((char*) startOfRemainder
.findTerminatingNull().getAddress()) - (char*) startOfRemainder
.getAddress();
1171 const size_t newTotalBytes
= initialBytes
+ newStringBytes
+ remainderBytes
;
1172 if (newTotalBytes
<= 0)
1173 return String::empty
;
1175 String
result (PreallocationBytes ((size_t) newTotalBytes
));
1177 char* dest
= (char*) result
.text
.getAddress();
1178 memcpy (dest
, text
.getAddress(), initialBytes
);
1179 dest
+= initialBytes
;
1180 memcpy (dest
, stringToInsert
.text
.getAddress(), newStringBytes
);
1181 dest
+= newStringBytes
;
1182 memcpy (dest
, startOfRemainder
.getAddress(), remainderBytes
);
1183 dest
+= remainderBytes
;
1184 CharPointerType ((CharPointerType::CharType
*) dest
).writeNull();
1189 String
String::replace (const String
& stringToReplace
, const String
& stringToInsert
, const bool ignoreCase
) const
1191 const int stringToReplaceLen
= stringToReplace
.length();
1192 const int stringToInsertLen
= stringToInsert
.length();
1195 String
result (*this);
1197 while ((i
= (ignoreCase
? result
.indexOfIgnoreCase (i
, stringToReplace
)
1198 : result
.indexOf (i
, stringToReplace
))) >= 0)
1200 result
= result
.replaceSection (i
, stringToReplaceLen
, stringToInsert
);
1201 i
+= stringToInsertLen
;
1207 class StringCreationHelper
1210 StringCreationHelper (const size_t initialBytes
)
1211 : source (nullptr), dest (nullptr), allocatedBytes (initialBytes
), bytesWritten (0)
1213 result
.preallocateBytes (allocatedBytes
);
1214 dest
= result
.getCharPointer();
1217 StringCreationHelper (const String::CharPointerType
& source_
)
1218 : source (source_
), dest (nullptr), allocatedBytes (StringHolder::getAllocatedNumBytes (source
)), bytesWritten (0)
1220 result
.preallocateBytes (allocatedBytes
);
1221 dest
= result
.getCharPointer();
1224 void write (juce_wchar c
)
1226 bytesWritten
+= String::CharPointerType::getBytesRequiredFor (c
);
1228 if (bytesWritten
> allocatedBytes
)
1230 allocatedBytes
+= jmax ((size_t) 8, allocatedBytes
/ 16);
1231 const size_t destOffset
= ((char*) dest
.getAddress()) - (char*) result
.getCharPointer().getAddress();
1232 result
.preallocateBytes (allocatedBytes
);
1233 dest
= addBytesToPointer (result
.getCharPointer().getAddress(), (int) destOffset
);
1240 String::CharPointerType source
;
1243 String::CharPointerType dest
;
1244 size_t allocatedBytes
, bytesWritten
;
1247 String
String::replaceCharacter (const juce_wchar charToReplace
, const juce_wchar charToInsert
) const
1249 if (! containsChar (charToReplace
))
1252 StringCreationHelper
builder (text
);
1256 juce_wchar c
= builder
.source
.getAndAdvance();
1258 if (c
== charToReplace
)
1267 return builder
.result
;
1270 String
String::replaceCharacters (const String
& charactersToReplace
, const String
& charactersToInsertInstead
) const
1272 StringCreationHelper
builder (text
);
1276 juce_wchar c
= builder
.source
.getAndAdvance();
1278 const int index
= charactersToReplace
.indexOfChar (c
);
1280 c
= charactersToInsertInstead
[index
];
1288 return builder
.result
;
1291 //==============================================================================
1292 bool String::startsWith (const String
& other
) const noexcept
1294 return text
.compareUpTo (other
.text
, other
.length()) == 0;
1297 bool String::startsWithIgnoreCase (const String
& other
) const noexcept
1299 return text
.compareIgnoreCaseUpTo (other
.text
, other
.length()) == 0;
1302 bool String::startsWithChar (const juce_wchar character
) const noexcept
1304 jassert (character
!= 0); // strings can't contain a null character!
1306 return *text
== character
;
1309 bool String::endsWithChar (const juce_wchar character
) const noexcept
1311 jassert (character
!= 0); // strings can't contain a null character!
1316 CharPointerType
t (text
.findTerminatingNull());
1317 return *--t
== character
;
1320 bool String::endsWith (const String
& other
) const noexcept
1322 CharPointerType
end (text
.findTerminatingNull());
1323 CharPointerType
otherEnd (other
.text
.findTerminatingNull());
1325 while (end
> text
&& otherEnd
> other
.text
)
1330 if (*end
!= *otherEnd
)
1334 return otherEnd
== other
.text
;
1337 bool String::endsWithIgnoreCase (const String
& other
) const noexcept
1339 CharPointerType
end (text
.findTerminatingNull());
1340 CharPointerType
otherEnd (other
.text
.findTerminatingNull());
1342 while (end
> text
&& otherEnd
> other
.text
)
1347 if (end
.toLowerCase() != otherEnd
.toLowerCase())
1351 return otherEnd
== other
.text
;
1354 //==============================================================================
1355 String
String::toUpperCase() const
1357 StringCreationHelper
builder (text
);
1361 const juce_wchar c
= builder
.source
.toUpperCase();
1369 return builder
.result
;
1372 String
String::toLowerCase() const
1374 StringCreationHelper
builder (text
);
1378 const juce_wchar c
= builder
.source
.toLowerCase();
1386 return builder
.result
;
1389 //==============================================================================
1390 juce_wchar
String::getLastCharacter() const noexcept
1392 return isEmpty() ? juce_wchar() : text
[length() - 1];
1395 String
String::substring (int start
, const int end
) const
1404 CharPointerType
t1 (text
);
1415 CharPointerType
t2 (t1
);
1430 return String (t1
, t2
);
1433 String
String::substring (int start
) const
1438 CharPointerType
t (text
);
1440 while (--start
>= 0)
1451 String
String::dropLastCharacters (const int numberToDrop
) const
1453 return String (text
, jmax (0, length() - numberToDrop
));
1456 String
String::getLastCharacters (const int numCharacters
) const
1458 return String (text
+ jmax (0, length() - jmax (0, numCharacters
)));
1461 String
String::fromFirstOccurrenceOf (const String
& sub
,
1462 const bool includeSubString
,
1463 const bool ignoreCase
) const
1465 const int i
= ignoreCase
? indexOfIgnoreCase (sub
)
1470 return substring (includeSubString
? i
: i
+ sub
.length());
1473 String
String::fromLastOccurrenceOf (const String
& sub
,
1474 const bool includeSubString
,
1475 const bool ignoreCase
) const
1477 const int i
= ignoreCase
? lastIndexOfIgnoreCase (sub
)
1478 : lastIndexOf (sub
);
1482 return substring (includeSubString
? i
: i
+ sub
.length());
1485 String
String::upToFirstOccurrenceOf (const String
& sub
,
1486 const bool includeSubString
,
1487 const bool ignoreCase
) const
1489 const int i
= ignoreCase
? indexOfIgnoreCase (sub
)
1494 return substring (0, includeSubString
? i
+ sub
.length() : i
);
1497 String
String::upToLastOccurrenceOf (const String
& sub
,
1498 const bool includeSubString
,
1499 const bool ignoreCase
) const
1501 const int i
= ignoreCase
? lastIndexOfIgnoreCase (sub
)
1502 : lastIndexOf (sub
);
1506 return substring (0, includeSubString
? i
+ sub
.length() : i
);
1509 bool String::isQuotedString() const
1511 const String
trimmed (trimStart());
1513 return trimmed
[0] == '"'
1514 || trimmed
[0] == '\'';
1517 String
String::unquoted() const
1519 const int len
= length();
1524 const juce_wchar lastChar
= text
[len
- 1];
1525 const int dropAtStart
= (*text
== '"' || *text
== '\'') ? 1 : 0;
1526 const int dropAtEnd
= (lastChar
== '"' || lastChar
== '\'') ? 1 : 0;
1528 return substring (dropAtStart
, len
- dropAtEnd
);
1531 String
String::quoted (const juce_wchar quoteCharacter
) const
1534 return charToString (quoteCharacter
) + quoteCharacter
;
1538 if (! t
.startsWithChar (quoteCharacter
))
1539 t
= charToString (quoteCharacter
) + t
;
1541 if (! t
.endsWithChar (quoteCharacter
))
1542 t
+= quoteCharacter
;
1547 //==============================================================================
1548 static String::CharPointerType
findTrimmedEnd (const String::CharPointerType
& start
, String::CharPointerType end
)
1552 if (! (--end
).isWhitespace())
1562 String
String::trim() const
1566 CharPointerType
start (text
.findEndOfWhitespace());
1568 const CharPointerType
end (start
.findTerminatingNull());
1569 CharPointerType
trimmedEnd (findTrimmedEnd (start
, end
));
1571 if (trimmedEnd
<= start
)
1573 else if (text
< start
|| trimmedEnd
< end
)
1574 return String (start
, trimmedEnd
);
1580 String
String::trimStart() const
1584 const CharPointerType
t (text
.findEndOfWhitespace());
1593 String
String::trimEnd() const
1597 const CharPointerType
end (text
.findTerminatingNull());
1598 CharPointerType
trimmedEnd (findTrimmedEnd (text
, end
));
1600 if (trimmedEnd
< end
)
1601 return String (text
, trimmedEnd
);
1607 String
String::trimCharactersAtStart (const String
& charactersToTrim
) const
1609 CharPointerType
t (text
);
1611 while (charactersToTrim
.containsChar (*t
))
1614 return t
== text
? *this : String (t
);
1617 String
String::trimCharactersAtEnd (const String
& charactersToTrim
) const
1621 const CharPointerType
end (text
.findTerminatingNull());
1622 CharPointerType
trimmedEnd (end
);
1624 while (trimmedEnd
> text
)
1626 if (! charactersToTrim
.containsChar (*--trimmedEnd
))
1633 if (trimmedEnd
< end
)
1634 return String (text
, trimmedEnd
);
1640 //==============================================================================
1641 String
String::retainCharacters (const String
& charactersToRetain
) const
1646 StringCreationHelper
builder (text
);
1650 juce_wchar c
= builder
.source
.getAndAdvance();
1652 if (charactersToRetain
.containsChar (c
))
1660 return builder
.result
;
1663 String
String::removeCharacters (const String
& charactersToRemove
) const
1668 StringCreationHelper
builder (text
);
1672 juce_wchar c
= builder
.source
.getAndAdvance();
1674 if (! charactersToRemove
.containsChar (c
))
1681 return builder
.result
;
1684 String
String::initialSectionContainingOnly (const String
& permittedCharacters
) const
1686 CharPointerType
t (text
);
1688 while (! t
.isEmpty())
1690 if (! permittedCharacters
.containsChar (*t
))
1691 return String (text
, t
);
1699 String
String::initialSectionNotContaining (const String
& charactersToStopAt
) const
1701 CharPointerType
t (text
);
1703 while (! t
.isEmpty())
1705 if (charactersToStopAt
.containsChar (*t
))
1706 return String (text
, t
);
1714 bool String::containsOnly (const String
& chars
) const noexcept
1716 CharPointerType
t (text
);
1718 while (! t
.isEmpty())
1719 if (! chars
.containsChar (t
.getAndAdvance()))
1725 bool String::containsAnyOf (const String
& chars
) const noexcept
1727 CharPointerType
t (text
);
1729 while (! t
.isEmpty())
1730 if (chars
.containsChar (t
.getAndAdvance()))
1736 bool String::containsNonWhitespaceChars() const noexcept
1738 CharPointerType
t (text
);
1740 while (! t
.isEmpty())
1742 if (! t
.isWhitespace())
1751 // Note! The format parameter here MUST NOT be a reference, otherwise MS's va_start macro fails to work (but still compiles).
1752 String
String::formatted (const String pf
, ... )
1754 size_t bufferSize
= 256;
1759 va_start (args
, pf
);
1762 HeapBlock
<wchar_t> temp (bufferSize
);
1763 const int num
= (int) _vsnwprintf (temp
.getData(), bufferSize
- 1, pf
.toWideCharPointer(), args
);
1765 HeapBlock
<char> temp (bufferSize
);
1766 const int num
= (int) vsnprintf (temp
.getData(), bufferSize
- 1, pf
.toUTF8(), args
);
1768 HeapBlock
<wchar_t> temp (bufferSize
);
1769 const int num
= (int) vswprintf (temp
.getData(), bufferSize
- 1, pf
.toWideCharPointer(), args
);
1775 return String (temp
);
1779 if (num
== 0 || bufferSize
> 65536) // the upper limit is a sanity check to avoid situations where vprintf repeatedly
1780 break; // returns -1 because of an error rather than because it needs more space.
1786 //==============================================================================
1787 int String::getIntValue() const noexcept
1789 return text
.getIntValue32();
1792 int String::getTrailingIntValue() const noexcept
1796 CharPointerType
t (text
.findTerminatingNull());
1808 n
+= mult
* (*t
- '0');
1815 int64
String::getLargeIntValue() const noexcept
1817 return text
.getIntValue64();
1820 float String::getFloatValue() const noexcept
1822 return (float) getDoubleValue();
1825 double String::getDoubleValue() const noexcept
1827 return text
.getDoubleValue();
1830 static const char hexDigits
[] = "0123456789abcdef";
1832 template <typename Type
>
1835 static String
hexToString (Type v
)
1838 char* const end
= buffer
+ 32;
1844 *--t
= hexDigits
[(int) (v
& 15)];
1849 return String (t
, (int) (end
- t
) - 1);
1852 static Type
stringToHex (String::CharPointerType t
) noexcept
1856 while (! t
.isEmpty())
1858 const int hexValue
= CharacterFunctions::getHexDigitValue (t
.getAndAdvance());
1861 result
= (result
<< 4) | hexValue
;
1868 String
String::toHexString (const int number
)
1870 return HexConverter
<unsigned int>::hexToString ((unsigned int) number
);
1873 String
String::toHexString (const int64 number
)
1875 return HexConverter
<uint64
>::hexToString ((uint64
) number
);
1878 String
String::toHexString (const short number
)
1880 return toHexString ((int) (unsigned short) number
);
1883 String
String::toHexString (const void* const d
, const int size
, const int groupSize
)
1888 int numChars
= (size
* 2) + 2;
1890 numChars
+= size
/ groupSize
;
1892 String
s (PreallocationBytes (sizeof (CharPointerType::CharType
) * (size_t) numChars
));
1894 const unsigned char* data
= static_cast <const unsigned char*> (d
);
1895 CharPointerType
dest (s
.text
);
1897 for (int i
= 0; i
< size
; ++i
)
1899 const unsigned char nextByte
= *data
++;
1900 dest
.write ((juce_wchar
) hexDigits
[nextByte
>> 4]);
1901 dest
.write ((juce_wchar
) hexDigits
[nextByte
& 0xf]);
1903 if (groupSize
> 0 && (i
% groupSize
) == (groupSize
- 1) && i
< (size
- 1))
1904 dest
.write ((juce_wchar
) ' ');
1911 int String::getHexValue32() const noexcept
1913 return HexConverter
<int>::stringToHex (text
);
1916 int64
String::getHexValue64() const noexcept
1918 return HexConverter
<int64
>::stringToHex (text
);
1921 //==============================================================================
1922 String
String::createStringFromData (const void* const data_
, const int size
)
1924 const uint8
* const data
= static_cast <const uint8
*> (data_
);
1926 if (size
<= 0 || data
== nullptr)
1932 return charToString ((char) data
[0]);
1934 else if ((data
[0] == (uint8
) CharPointer_UTF16::byteOrderMarkBE1
&& data
[1] == (uint8
) CharPointer_UTF16::byteOrderMarkBE2
)
1935 || (data
[0] == (uint8
) CharPointer_UTF16::byteOrderMarkLE1
&& data
[1] == (uint8
) CharPointer_UTF16::byteOrderMarkLE2
))
1937 const bool bigEndian
= (data
[0] == (uint8
) CharPointer_UTF16::byteOrderMarkBE1
);
1938 const int numChars
= size
/ 2 - 1;
1940 StringCreationHelper
builder (numChars
);
1942 const uint16
* const src
= (const uint16
*) (data
+ 2);
1946 for (int i
= 0; i
< numChars
; ++i
)
1947 builder
.write ((juce_wchar
) ByteOrder::swapIfLittleEndian (src
[i
]));
1951 for (int i
= 0; i
< numChars
; ++i
)
1952 builder
.write ((juce_wchar
) ByteOrder::swapIfBigEndian (src
[i
]));
1956 return builder
.result
;
1960 const uint8
* start
= data
;
1961 const uint8
* end
= data
+ size
;
1964 && data
[0] == (uint8
) CharPointer_UTF8::byteOrderMark1
1965 && data
[1] == (uint8
) CharPointer_UTF8::byteOrderMark2
1966 && data
[2] == (uint8
) CharPointer_UTF8::byteOrderMark3
)
1969 return String (CharPointer_UTF8 ((const char*) start
),
1970 CharPointer_UTF8 ((const char*) end
));
1974 //==============================================================================
1975 static juce_wchar emptyChar
= 0;
1977 template <class CharPointerType_Src
, class CharPointerType_Dest
>
1978 struct StringEncodingConverter
1980 static const CharPointerType_Dest
convert (const String
& s
)
1982 String
& source
= const_cast <String
&> (s
);
1984 typedef typename
CharPointerType_Dest::CharType DestChar
;
1986 if (source
.isEmpty())
1987 return CharPointerType_Dest (reinterpret_cast <const DestChar
*> (&emptyChar
));
1989 CharPointerType_Src
text (source
.getCharPointer());
1990 const size_t extraBytesNeeded
= CharPointerType_Dest::getBytesRequiredFor (text
);
1991 const size_t endOffset
= (text
.sizeInBytes() + 3) & ~3; // the new string must be word-aligned or many win32
1992 // functions will fail to read it correctly!
1993 source
.preallocateBytes (endOffset
+ extraBytesNeeded
);
1994 text
= source
.getCharPointer();
1996 void* newSpace
= addBytesToPointer (text
.getAddress(), (int) endOffset
);
1997 const CharPointerType_Dest
extraSpace (static_cast <DestChar
*> (newSpace
));
1999 #if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..)
2000 const int bytesToClear
= jmin ((int) extraBytesNeeded
, 4);
2001 zeromem (addBytesToPointer (newSpace
, (int) (extraBytesNeeded
- bytesToClear
)), bytesToClear
);
2004 CharPointerType_Dest (extraSpace
).writeAll (text
);
2010 struct StringEncodingConverter
<CharPointer_UTF8
, CharPointer_UTF8
>
2012 static const CharPointer_UTF8
convert (const String
& source
) noexcept
{ return CharPointer_UTF8 ((CharPointer_UTF8::CharType
*) source
.getCharPointer().getAddress()); }
2016 struct StringEncodingConverter
<CharPointer_UTF16
, CharPointer_UTF16
>
2018 static const CharPointer_UTF16
convert (const String
& source
) noexcept
{ return CharPointer_UTF16 ((CharPointer_UTF16::CharType
*) source
.getCharPointer().getAddress()); }
2022 struct StringEncodingConverter
<CharPointer_UTF32
, CharPointer_UTF32
>
2024 static const CharPointer_UTF32
convert (const String
& source
) noexcept
{ return CharPointer_UTF32 ((CharPointer_UTF32::CharType
*) source
.getCharPointer().getAddress()); }
2027 const CharPointer_UTF8
String::toUTF8() const
2029 return StringEncodingConverter
<CharPointerType
, CharPointer_UTF8
>::convert (*this);
2032 CharPointer_UTF16
String::toUTF16() const
2034 return StringEncodingConverter
<CharPointerType
, CharPointer_UTF16
>::convert (*this);
2037 CharPointer_UTF32
String::toUTF32() const
2039 return StringEncodingConverter
<CharPointerType
, CharPointer_UTF32
>::convert (*this);
2042 const wchar_t* String::toWideCharPointer() const
2044 return (const wchar_t*) StringEncodingConverter
<CharPointerType
, CharPointer_wchar_t
>::convert (*this).getAddress();
2047 //==============================================================================
2048 template <class CharPointerType_Src
, class CharPointerType_Dest
>
2051 static int copyToBuffer (const CharPointerType_Src
& source
, typename
CharPointerType_Dest::CharType
* const buffer
, const int maxBufferSizeBytes
)
2053 jassert (maxBufferSizeBytes
>= 0); // keep this value positive, or no characters will be copied!
2055 if (buffer
== nullptr)
2056 return (int) (CharPointerType_Dest::getBytesRequiredFor (source
) + sizeof (typename
CharPointerType_Dest::CharType
));
2058 return CharPointerType_Dest (buffer
).writeWithDestByteLimit (source
, maxBufferSizeBytes
);
2062 int String::copyToUTF8 (CharPointer_UTF8::CharType
* const buffer
, const int maxBufferSizeBytes
) const noexcept
2064 return StringCopier
<CharPointerType
, CharPointer_UTF8
>::copyToBuffer (text
, buffer
, maxBufferSizeBytes
);
2067 int String::copyToUTF16 (CharPointer_UTF16::CharType
* const buffer
, int maxBufferSizeBytes
) const noexcept
2069 return StringCopier
<CharPointerType
, CharPointer_UTF16
>::copyToBuffer (text
, buffer
, maxBufferSizeBytes
);
2072 int String::copyToUTF32 (CharPointer_UTF32::CharType
* const buffer
, int maxBufferSizeBytes
) const noexcept
2074 return StringCopier
<CharPointerType
, CharPointer_UTF32
>::copyToBuffer (text
, buffer
, maxBufferSizeBytes
);
2077 //==============================================================================
2078 int String::getNumBytesAsUTF8() const noexcept
2080 return (int) CharPointer_UTF8::getBytesRequiredFor (text
);
2083 String
String::fromUTF8 (const char* const buffer
, int bufferSizeBytes
)
2085 if (buffer
!= nullptr)
2087 if (bufferSizeBytes
< 0)
2088 return String (CharPointer_UTF8 (buffer
));
2089 else if (bufferSizeBytes
> 0)
2090 return String (CharPointer_UTF8 (buffer
), CharPointer_UTF8 (buffer
+ bufferSizeBytes
));
2093 return String::empty
;
2097 #pragma warning (pop)
2100 //==============================================================================
2101 String::Concatenator::Concatenator (String
& stringToAppendTo
)
2102 : result (stringToAppendTo
),
2103 nextIndex (stringToAppendTo
.length())
2107 String::Concatenator::~Concatenator()
2111 void String::Concatenator::append (const String
& s
)
2113 const int len
= s
.length();
2117 size_t extraBytes
= s
.getCharPointer().sizeInBytes();
2118 result
.preallocateBytes (nextIndex
+ extraBytes
);
2119 CharPointerType (result
.text
+ nextIndex
).writeAll (s
.text
);
2125 //==============================================================================
2126 //==============================================================================
2129 #include "../utilities/juce_UnitTest.h"
2130 #include "../maths/juce_Random.h"
2131 #include "juce_StringArray.h"
2133 class StringTests
: public UnitTest
2136 StringTests() : UnitTest ("String class") {}
2138 template <class CharPointerType
>
2139 struct TestUTFConversion
2141 static void test (UnitTest
& test
)
2143 String
s (createRandomWideCharString());
2145 typename
CharPointerType::CharType buffer
[300];
2147 memset (buffer
, 0xff, sizeof (buffer
));
2148 CharPointerType (buffer
).writeAll (s
.toUTF32());
2149 test
.expectEquals (String (CharPointerType (buffer
)), s
);
2151 memset (buffer
, 0xff, sizeof (buffer
));
2152 CharPointerType (buffer
).writeAll (s
.toUTF16());
2153 test
.expectEquals (String (CharPointerType (buffer
)), s
);
2155 memset (buffer
, 0xff, sizeof (buffer
));
2156 CharPointerType (buffer
).writeAll (s
.toUTF8());
2157 test
.expectEquals (String (CharPointerType (buffer
)), s
);
2161 static String
createRandomWideCharString()
2163 juce_wchar buffer
[50] = { 0 };
2165 for (int i
= 0; i
< numElementsInArray (buffer
) - 1; ++i
)
2167 if (Random::getSystemRandom().nextBool())
2171 buffer
[i
] = (juce_wchar
) (1 + Random::getSystemRandom().nextInt (0x10ffff - 1));
2173 while (! CharPointer_UTF16::canRepresent (buffer
[i
]));
2176 buffer
[i
] = (juce_wchar
) (1 + Random::getSystemRandom().nextInt (0xff));
2179 return CharPointer_UTF32 (buffer
);
2185 beginTest ("Basics");
2187 expect (String().length() == 0);
2188 expect (String() == String::empty
);
2189 String s1
, s2 ("abcd");
2190 expect (s1
.isEmpty() && ! s1
.isNotEmpty());
2191 expect (s2
.isNotEmpty() && ! s2
.isEmpty());
2192 expect (s2
.length() == 4);
2194 expect (s2
== s1
&& s1
== s2
);
2195 expect (s1
== "abcd" && s1
== L
"abcd");
2196 expect (String ("abcd") == String (L
"abcd"));
2197 expect (String ("abcdefg", 4) == L
"abcd");
2198 expect (String ("abcdefg", 4) == String (L
"abcdefg", 4));
2199 expect (String::charToString ('x') == "x");
2200 expect (String::charToString (0) == String::empty
);
2201 expect (s2
+ "e" == "abcde" && s2
+ 'e' == "abcde");
2202 expect (s2
+ L
'e' == "abcde" && s2
+ L
"e" == "abcde");
2203 expect (s1
.equalsIgnoreCase ("abcD") && s1
< "abce" && s1
> "abbb");
2204 expect (s1
.startsWith ("ab") && s1
.startsWith ("abcd") && ! s1
.startsWith ("abcde"));
2205 expect (s1
.startsWithIgnoreCase ("aB") && s1
.endsWithIgnoreCase ("CD"));
2206 expect (s1
.endsWith ("bcd") && ! s1
.endsWith ("aabcd"));
2207 expectEquals (s1
.indexOf (String::empty
), 0);
2208 expectEquals (s1
.indexOfIgnoreCase (String::empty
), 0);
2209 expect (s1
.startsWith (String::empty
) && s1
.endsWith (String::empty
) && s1
.contains (String::empty
));
2210 expect (s1
.contains ("cd") && s1
.contains ("ab") && s1
.contains ("abcd"));
2211 expect (s1
.containsChar ('a'));
2212 expect (! s1
.containsChar ('x'));
2213 expect (! s1
.containsChar (0));
2214 expect (String ("abc foo bar").containsWholeWord ("abc") && String ("abc foo bar").containsWholeWord ("abc"));
2218 beginTest ("Operations");
2220 String
s ("012345678");
2221 expect (s
.hashCode() != 0);
2222 expect (s
.hashCode64() != 0);
2223 expect (s
.hashCode() != (s
+ s
).hashCode());
2224 expect (s
.hashCode64() != (s
+ s
).hashCode64());
2225 expect (s
.compare (String ("012345678")) == 0);
2226 expect (s
.compare (String ("012345679")) < 0);
2227 expect (s
.compare (String ("012345676")) > 0);
2228 expect (s
.substring (2, 3) == String::charToString (s
[2]));
2229 expect (s
.substring (0, 1) == String::charToString (s
[0]));
2230 expect (s
.getLastCharacter() == s
[s
.length() - 1]);
2231 expect (String::charToString (s
.getLastCharacter()) == s
.getLastCharacters (1));
2232 expect (s
.substring (0, 3) == L
"012");
2233 expect (s
.substring (0, 100) == s
);
2234 expect (s
.substring (-1, 100) == s
);
2235 expect (s
.substring (3) == "345678");
2236 expect (s
.indexOf (L
"45") == 4);
2237 expect (String ("444445").indexOf ("45") == 4);
2238 expect (String ("444445").lastIndexOfChar ('4') == 4);
2239 expect (String ("45454545x").lastIndexOf (L
"45") == 6);
2240 expect (String ("45454545x").lastIndexOfAnyOf ("456") == 7);
2241 expect (String ("45454545x").lastIndexOfAnyOf (L
"456x") == 8);
2242 expect (String ("abABaBaBa").lastIndexOfIgnoreCase ("aB") == 6);
2243 expect (s
.indexOfChar (L
'4') == 4);
2244 expect (s
+ s
== "012345678012345678");
2245 expect (s
.startsWith (s
));
2246 expect (s
.startsWith (s
.substring (0, 4)));
2247 expect (s
.startsWith (s
.dropLastCharacters (4)));
2248 expect (s
.endsWith (s
.substring (5)));
2249 expect (s
.endsWith (s
));
2250 expect (s
.contains (s
.substring (3, 6)));
2251 expect (s
.contains (s
.substring (3)));
2252 expect (s
.startsWithChar (s
[0]));
2253 expect (s
.endsWithChar (s
.getLastCharacter()));
2254 expect (s
[s
.length()] == 0);
2255 expect (String ("abcdEFGH").toLowerCase() == String ("abcdefgh"));
2256 expect (String ("abcdEFGH").toUpperCase() == String ("ABCDEFGH"));
2259 s2
<< ((int) 4) << ((short) 5) << "678" << L
"9" << '0';
2261 expect (s2
== "1234567890xyz");
2263 beginTest ("Numeric conversions");
2264 expect (String::empty
.getIntValue() == 0);
2265 expect (String::empty
.getDoubleValue() == 0.0);
2266 expect (String::empty
.getFloatValue() == 0.0f
);
2267 expect (s
.getIntValue() == 12345678);
2268 expect (s
.getLargeIntValue() == (int64
) 12345678);
2269 expect (s
.getDoubleValue() == 12345678.0);
2270 expect (s
.getFloatValue() == 12345678.0f
);
2271 expect (String (-1234).getIntValue() == -1234);
2272 expect (String ((int64
) -1234).getLargeIntValue() == -1234);
2273 expect (String (-1234.56).getDoubleValue() == -1234.56);
2274 expect (String (-1234.56f
).getFloatValue() == -1234.56f
);
2275 expect (("xyz" + s
).getTrailingIntValue() == s
.getIntValue());
2276 expect (s
.getHexValue32() == 0x12345678);
2277 expect (s
.getHexValue64() == (int64
) 0x12345678);
2278 expect (String::toHexString (0x1234abcd).equalsIgnoreCase ("1234abcd"));
2279 expect (String::toHexString ((int64
) 0x1234abcd).equalsIgnoreCase ("1234abcd"));
2280 expect (String::toHexString ((short) 0x12ab).equalsIgnoreCase ("12ab"));
2282 unsigned char data
[] = { 1, 2, 3, 4, 0xa, 0xb, 0xc, 0xd };
2283 expect (String::toHexString (data
, 8, 0).equalsIgnoreCase ("010203040a0b0c0d"));
2284 expect (String::toHexString (data
, 8, 1).equalsIgnoreCase ("01 02 03 04 0a 0b 0c 0d"));
2285 expect (String::toHexString (data
, 8, 2).equalsIgnoreCase ("0102 0304 0a0b 0c0d"));
2287 beginTest ("Subsections");
2290 expect (s3
.equalsIgnoreCase ("ABCdeFGhiJ"));
2291 expect (s3
.compareIgnoreCase (L
"ABCdeFGhiJ") == 0);
2292 expect (s3
.containsIgnoreCase (s3
.substring (3)));
2293 expect (s3
.indexOfAnyOf ("xyzf", 2, true) == 5);
2294 expect (s3
.indexOfAnyOf (L
"xyzf", 2, false) == -1);
2295 expect (s3
.indexOfAnyOf ("xyzF", 2, false) == 5);
2296 expect (s3
.containsAnyOf (L
"zzzFs"));
2297 expect (s3
.startsWith ("abcd"));
2298 expect (s3
.startsWithIgnoreCase (L
"abCD"));
2299 expect (s3
.startsWith (String::empty
));
2300 expect (s3
.startsWithChar ('a'));
2301 expect (s3
.endsWith (String ("HIJ")));
2302 expect (s3
.endsWithIgnoreCase (L
"Hij"));
2303 expect (s3
.endsWith (String::empty
));
2304 expect (s3
.endsWithChar (L
'J'));
2305 expect (s3
.indexOf ("HIJ") == 7);
2306 expect (s3
.indexOf (L
"HIJK") == -1);
2307 expect (s3
.indexOfIgnoreCase ("hij") == 7);
2308 expect (s3
.indexOfIgnoreCase (L
"hijk") == -1);
2311 s4
.append (String ("xyz123"), 3);
2312 expect (s4
== s3
+ "xyz");
2314 expect (String (1234) < String (1235));
2315 expect (String (1235) > String (1234));
2316 expect (String (1234) >= String (1234));
2317 expect (String (1234) <= String (1234));
2318 expect (String (1235) >= String (1234));
2319 expect (String (1234) <= String (1235));
2321 String
s5 ("word word2 word3");
2322 expect (s5
.containsWholeWord (String ("word2")));
2323 expect (s5
.indexOfWholeWord ("word2") == 5);
2324 expect (s5
.containsWholeWord (L
"word"));
2325 expect (s5
.containsWholeWord ("word3"));
2326 expect (s5
.containsWholeWord (s5
));
2327 expect (s5
.containsWholeWordIgnoreCase (L
"Word2"));
2328 expect (s5
.indexOfWholeWordIgnoreCase ("Word2") == 5);
2329 expect (s5
.containsWholeWordIgnoreCase (L
"Word"));
2330 expect (s5
.containsWholeWordIgnoreCase ("Word3"));
2331 expect (! s5
.containsWholeWordIgnoreCase (L
"Wordx"));
2332 expect (!s5
.containsWholeWordIgnoreCase ("xWord2"));
2333 expect (s5
.containsNonWhitespaceChars());
2334 expect (s5
.containsOnly ("ordw23 "));
2335 expect (! String (" \n\r\t").containsNonWhitespaceChars());
2337 expect (s5
.matchesWildcard (L
"wor*", false));
2338 expect (s5
.matchesWildcard ("wOr*", true));
2339 expect (s5
.matchesWildcard (L
"*word3", true));
2340 expect (s5
.matchesWildcard ("*word?", true));
2341 expect (s5
.matchesWildcard (L
"Word*3", true));
2343 expectEquals (s5
.fromFirstOccurrenceOf (String::empty
, true, false), s5
);
2344 expectEquals (s5
.fromFirstOccurrenceOf ("xword2", true, false), s5
.substring (100));
2345 expectEquals (s5
.fromFirstOccurrenceOf (L
"word2", true, false), s5
.substring (5));
2346 expectEquals (s5
.fromFirstOccurrenceOf ("Word2", true, true), s5
.substring (5));
2347 expectEquals (s5
.fromFirstOccurrenceOf ("word2", false, false), s5
.getLastCharacters (6));
2348 expectEquals (s5
.fromFirstOccurrenceOf (L
"Word2", false, true), s5
.getLastCharacters (6));
2350 expectEquals (s5
.fromLastOccurrenceOf (String::empty
, true, false), s5
);
2351 expectEquals (s5
.fromLastOccurrenceOf (L
"wordx", true, false), s5
);
2352 expectEquals (s5
.fromLastOccurrenceOf ("word", true, false), s5
.getLastCharacters (5));
2353 expectEquals (s5
.fromLastOccurrenceOf (L
"worD", true, true), s5
.getLastCharacters (5));
2354 expectEquals (s5
.fromLastOccurrenceOf ("word", false, false), s5
.getLastCharacters (1));
2355 expectEquals (s5
.fromLastOccurrenceOf (L
"worD", false, true), s5
.getLastCharacters (1));
2357 expect (s5
.upToFirstOccurrenceOf (String::empty
, true, false).isEmpty());
2358 expectEquals (s5
.upToFirstOccurrenceOf ("word4", true, false), s5
);
2359 expectEquals (s5
.upToFirstOccurrenceOf (L
"word2", true, false), s5
.substring (0, 10));
2360 expectEquals (s5
.upToFirstOccurrenceOf ("Word2", true, true), s5
.substring (0, 10));
2361 expectEquals (s5
.upToFirstOccurrenceOf (L
"word2", false, false), s5
.substring (0, 5));
2362 expectEquals (s5
.upToFirstOccurrenceOf ("Word2", false, true), s5
.substring (0, 5));
2364 expectEquals (s5
.upToLastOccurrenceOf (String::empty
, true, false), s5
);
2365 expectEquals (s5
.upToLastOccurrenceOf ("zword", true, false), s5
);
2366 expectEquals (s5
.upToLastOccurrenceOf ("word", true, false), s5
.dropLastCharacters (1));
2367 expectEquals (s5
.dropLastCharacters(1).upToLastOccurrenceOf ("word", true, false), s5
.dropLastCharacters (1));
2368 expectEquals (s5
.upToLastOccurrenceOf ("Word", true, true), s5
.dropLastCharacters (1));
2369 expectEquals (s5
.upToLastOccurrenceOf ("word", false, false), s5
.dropLastCharacters (5));
2370 expectEquals (s5
.upToLastOccurrenceOf ("Word", false, true), s5
.dropLastCharacters (5));
2372 expectEquals (s5
.replace ("word", L
"xyz", false), String ("xyz xyz2 xyz3"));
2373 expect (s5
.replace (L
"Word", "xyz", true) == "xyz xyz2 xyz3");
2374 expect (s5
.dropLastCharacters (1).replace ("Word", String ("xyz"), true) == L
"xyz xyz2 xyz");
2375 expect (s5
.replace ("Word", "", true) == " 2 3");
2376 expectEquals (s5
.replace ("Word2", L
"xyz", true), String ("word xyz word3"));
2377 expect (s5
.replaceCharacter (L
'w', 'x') != s5
);
2378 expectEquals (s5
.replaceCharacter ('w', L
'x').replaceCharacter ('x', 'w'), s5
);
2379 expect (s5
.replaceCharacters ("wo", "xy") != s5
);
2380 expectEquals (s5
.replaceCharacters ("wo", "xy").replaceCharacters ("xy", L
"wo"), s5
);
2381 expectEquals (s5
.retainCharacters ("1wordxya"), String ("wordwordword"));
2382 expect (s5
.retainCharacters (String::empty
).isEmpty());
2383 expect (s5
.removeCharacters ("1wordxya") == " 2 3");
2384 expectEquals (s5
.removeCharacters (String::empty
), s5
);
2385 expect (s5
.initialSectionContainingOnly ("word") == L
"word");
2386 expect (String ("word").initialSectionContainingOnly ("word") == L
"word");
2387 expectEquals (s5
.initialSectionNotContaining (String ("xyz ")), String ("word"));
2388 expectEquals (s5
.initialSectionNotContaining (String (";[:'/")), s5
);
2389 expect (! s5
.isQuotedString());
2390 expect (s5
.quoted().isQuotedString());
2391 expect (! s5
.quoted().unquoted().isQuotedString());
2392 expect (! String ("x'").isQuotedString());
2393 expect (String ("'x").isQuotedString());
2395 String
s6 (" \t xyz \t\r\n");
2396 expectEquals (s6
.trim(), String ("xyz"));
2397 expect (s6
.trim().trim() == "xyz");
2398 expectEquals (s5
.trim(), s5
);
2399 expectEquals (s6
.trimStart().trimEnd(), s6
.trim());
2400 expectEquals (s6
.trimStart().trimEnd(), s6
.trimEnd().trimStart());
2401 expectEquals (s6
.trimStart().trimStart().trimEnd().trimEnd(), s6
.trimEnd().trimStart());
2402 expect (s6
.trimStart() != s6
.trimEnd());
2403 expectEquals (("\t\r\n " + s6
+ "\t\n \r").trim(), s6
.trim());
2404 expect (String::repeatedString ("xyz", 3) == L
"xyzxyzxyz");
2408 beginTest ("UTF conversions");
2410 TestUTFConversion
<CharPointer_UTF32
>::test (*this);
2411 TestUTFConversion
<CharPointer_UTF8
>::test (*this);
2412 TestUTFConversion
<CharPointer_UTF16
>::test (*this);
2416 beginTest ("StringArray");
2419 for (int i
= 5; --i
>= 0;)
2422 expectEquals (s
.joinIntoString ("-"), String ("4-3-2-1-0"));
2424 expectEquals (s
.joinIntoString ("--"), String ("4--3--1--0"));
2425 expectEquals (s
.joinIntoString (String::empty
), String ("4310"));
2427 expectEquals (s
.joinIntoString ("x"), String::empty
);
2432 static StringTests stringUnitTests
;