27 #pragma warning (push)
28 #pragma warning (disable: 4514 4996)
33 #if defined (JUCE_STRINGS_ARE_UNICODE) && ! JUCE_STRINGS_ARE_UNICODE
34 #error "JUCE_STRINGS_ARE_UNICODE is deprecated! All strings are now unicode by default."
37 #if JUCE_NATIVE_WCHAR_IS_UTF8
38 using CharPointer_wchar_t = CharPointer_UTF8;
39 #elif JUCE_NATIVE_WCHAR_IS_UTF16
40 using CharPointer_wchar_t = CharPointer_UTF16;
42 using CharPointer_wchar_t = CharPointer_UTF32;
45 static inline CharPointer_wchar_t castToCharPointer_wchar_t (
const void* t) noexcept
47 return CharPointer_wchar_t (
static_cast<const CharPointer_wchar_t::CharType*
> (t));
55 size_t allocatedBytes;
56 String::CharPointerType::CharType text;
59 static const EmptyString emptyString = { 0x3fffffff,
sizeof (String::CharPointerType::CharType), 0 };
68 using CharType = String::CharPointerType::CharType;
73 numBytes = (numBytes + 3) & ~(
size_t) 3;
75 s->refCount.
value = 0;
76 s->allocatedNumBytes = numBytes;
80 template <
class CharPo
inter>
83 if (text.getAddress() ==
nullptr || text.isEmpty())
87 auto dest = createUninitialisedBytes (bytesNeeded);
92 template <
class CharPo
inter>
93 static CharPointerType createFromCharPointer (
const CharPointer text,
size_t maxChars)
95 if (text.getAddress() ==
nullptr || text.isEmpty() || maxChars == 0)
100 size_t bytesNeeded =
sizeof (CharType);
102 while (numChars < maxChars && ! end.isEmpty())
108 auto dest = createUninitialisedBytes (bytesNeeded);
113 template <
class CharPo
inter>
114 static CharPointerType createFromCharPointer (
const CharPointer start,
const CharPointer end)
116 if (start.getAddress() ==
nullptr || start.isEmpty())
121 auto bytesNeeded =
sizeof (CharType);
123 while (e < end && ! e.isEmpty())
129 auto dest = createUninitialisedBytes (bytesNeeded);
139 auto numBytes = (size_t) (
reinterpret_cast<const char*
> (end.
getAddress())
140 -
reinterpret_cast<const char*
> (start.
getAddress()));
141 auto dest = createUninitialisedBytes (numBytes +
sizeof (CharType));
142 memcpy (dest.getAddress(), start, numBytes);
143 dest.getAddress()[numBytes /
sizeof (CharType)] = 0;
147 static CharPointerType createFromFixedLength (
const char*
const src,
const size_t numChars)
149 auto dest = createUninitialisedBytes (numChars *
sizeof (CharType) +
sizeof (CharType));
157 auto* b = bufferFromText (text);
163 static inline void release (
StringHolder*
const b) noexcept
166 if (--(b->refCount) == -1)
167 delete[]
reinterpret_cast<char*
> (b);
172 release (bufferFromText (text));
175 static inline int getReferenceCount (
const CharPointerType text) noexcept
177 return bufferFromText (text)->refCount.
get() + 1;
183 auto* b = bufferFromText (text);
187 auto newText = createUninitialisedBytes (numBytes);
192 if (b->allocatedNumBytes >= numBytes && b->refCount.
get() <= 0)
195 auto newText = createUninitialisedBytes (jmax (b->allocatedNumBytes, numBytes));
196 memcpy (newText.getAddress(), text.
getAddress(), b->allocatedNumBytes);
202 static size_t getAllocatedNumBytes (
const CharPointerType text) noexcept
204 return bufferFromText (text)->allocatedNumBytes;
209 size_t allocatedNumBytes;
217 - (
reinterpret_cast<size_t> (
reinterpret_cast<StringHolder*
> (128)->text) - 128));
220 void compileTimeChecks()
223 #if JUCE_NATIVE_WCHAR_IS_UTF8
224 static_assert (
sizeof (
wchar_t) == 1,
"JUCE_NATIVE_WCHAR_IS_* macro has incorrect value");
225 #elif JUCE_NATIVE_WCHAR_IS_UTF16
226 static_assert (
sizeof (
wchar_t) == 2,
"JUCE_NATIVE_WCHAR_IS_* macro has incorrect value");
227 #elif JUCE_NATIVE_WCHAR_IS_UTF32
228 static_assert (
sizeof (
wchar_t) == 4,
"JUCE_NATIVE_WCHAR_IS_* macro has incorrect value");
230 #error "native wchar_t size is unknown"
234 "StringHolder is not large enough to hold an empty String");
238 JUCE_DECLARE_DEPRECATED_STATIC (
const String String::empty;)
247 StringHolder::release (text);
252 StringHolder::retain (text);
257 std::swap (text, other.text);
262 StringHolder::release (text);
263 text = &(emptyString.text);
268 StringHolder::retain (other.text);
269 StringHolder::release (text.atomicSwap (other.text));
275 other.text = &(emptyString.text);
280 std::swap (text, other.text);
284 inline String::PreallocationBytes::PreallocationBytes (
const size_t num) noexcept : numBytes (num) {}
287 : text (StringHolder::createUninitialisedBytes (preallocationSize.numBytes + sizeof (CharPointerType::CharType)))
293 text = StringHolder::makeUniqueWithByteSize (text, numBytesNeeded +
sizeof (CharPointerType::CharType));
298 return StringHolder::getReferenceCount (text);
376 namespace NumberToStringConverters
380 charsNeededForInt = 32,
381 charsNeededForDouble = 48
384 template <
typename Type>
385 static char* printDigits (
char* t, Type v) noexcept
391 *--t =
'0' + (char) (v % 10);
400 static char* numberToString (
char* t, int64 n) noexcept
403 return printDigits (t,
static_cast<uint64
> (n));
407 t = printDigits (t,
static_cast<uint64
> (-(n + 1)) + 1);
412 static char* numberToString (
char* t, uint64 v) noexcept
414 return printDigits (t, v);
417 static char* numberToString (
char* t,
int n) noexcept
420 return printDigits (t,
static_cast<unsigned int> (n));
424 t = printDigits (t,
static_cast<unsigned int> (-(n + 1)) + 1);
429 static char* numberToString (
char* t,
unsigned int v) noexcept
431 return printDigits (t, v);
434 static char* numberToString (
char* t,
long n) noexcept
437 return printDigits (t,
static_cast<unsigned long> (n));
439 t = printDigits (t,
static_cast<unsigned long> (-(n + 1)) + 1);
444 static char* numberToString (
char* t,
unsigned long v) noexcept
446 return printDigits (t, v);
453 static const std::locale classicLocale (std::locale::classic());
454 imbue (classicLocale);
455 setp (d, d + charsNeededForDouble);
458 size_t writeDouble (
double n,
int numDecPlaces,
bool useScientificNotation)
461 std::ostream o (
this);
463 if (numDecPlaces > 0)
465 o.setf (useScientificNotation ? std::ios_base::scientific : std::ios_base::fixed);
466 o.precision ((std::streamsize) numDecPlaces);
472 return (
size_t) (pptr() - pbase());
476 static char* doubleToString (
char* buffer,
double n,
int numDecPlaces,
bool useScientificNotation,
size_t& len) noexcept
479 len = strm.writeDouble (n, numDecPlaces, useScientificNotation);
480 jassert (len <= charsNeededForDouble);
484 template <
typename IntegerType>
487 char buffer [charsNeededForInt];
488 auto* end = buffer + numElementsInArray (buffer);
489 auto* start = numberToString (end, number);
490 return StringHolder::createFromFixedLength (start, (
size_t) (end - start - 1));
493 static String::CharPointerType createFromDouble (
double number,
int numberOfDecimalPlaces,
bool useScientificNotation)
495 char buffer [charsNeededForDouble];
497 auto start = doubleToString (buffer, number, numberOfDecimalPlaces, useScientificNotation, len);
498 return StringHolder::createFromFixedLength (start, len);
503 String::String (
int number) : text (NumberToStringConverters::createFromInteger (number)) {}
504 String::String (
unsigned int number) : text (NumberToStringConverters::createFromInteger (number)) {}
505 String::String (
short number) : text (NumberToStringConverters::createFromInteger ((int) number)) {}
506 String::String (
unsigned short number) : text (NumberToStringConverters::createFromInteger ((unsigned int) number)) {}
507 String::String (int64 number) : text (NumberToStringConverters::createFromInteger (number)) {}
508 String::String (uint64 number) : text (NumberToStringConverters::createFromInteger (number)) {}
509 String::String (
long number) : text (NumberToStringConverters::createFromInteger (number)) {}
510 String::String (
unsigned long number) : text (NumberToStringConverters::createFromInteger (number)) {}
512 String::String (
float number) : text (NumberToStringConverters::createFromDouble ((double) number, 0, false)) {}
513 String::String (
double number) : text (NumberToStringConverters::createFromDouble ( number, 0, false)) {}
514 String::String (
float number,
int numberOfDecimalPlaces,
bool useScientificNotation) : text (NumberToStringConverters::createFromDouble ((double) number, numberOfDecimalPlaces, useScientificNotation)) {}
515 String::String (
double number,
int numberOfDecimalPlaces,
bool useScientificNotation) : text (NumberToStringConverters::createFromDouble ( number, numberOfDecimalPlaces, useScientificNotation)) {}
520 return (
int) text.
length();
525 return (
size_t) (((
char*) text.findTerminatingNull().getAddress()) - (
char*) text.getAddress());
528 size_t String::getByteOffsetOfEnd() const noexcept
530 return findByteOffsetOfEnd (text);
535 jassert (index == 0 || (index > 0 && index <= (
int) text.lengthUpTo ((
size_t) index + 1)));
539 template <
typename Type>
542 template <
typename CharPo
inter>
543 static Type calculate (CharPointer t) noexcept
547 while (! t.isEmpty())
548 result = ((Type) multiplier) * result + (Type) t.getAndAdvance();
553 enum { multiplier =
sizeof (Type) > 4 ? 101 : 31 };
561 JUCE_API bool JUCE_CALLTYPE operator== (
const String& s1,
const String& s2) noexcept {
return s1.compare (s2) == 0; }
562 JUCE_API bool JUCE_CALLTYPE operator!= (
const String& s1,
const String& s2) noexcept {
return s1.compare (s2) != 0; }
563 JUCE_API bool JUCE_CALLTYPE operator== (
const String& s1,
const char* s2) noexcept {
return s1.compare (s2) == 0; }
564 JUCE_API bool JUCE_CALLTYPE operator!= (
const String& s1,
const char* s2) noexcept {
return s1.compare (s2) != 0; }
565 JUCE_API bool JUCE_CALLTYPE operator== (
const String& s1,
const wchar_t* s2) noexcept {
return s1.compare (s2) == 0; }
566 JUCE_API bool JUCE_CALLTYPE operator!= (
const String& s1,
const wchar_t* s2) noexcept {
return s1.compare (s2) != 0; }
567 JUCE_API bool JUCE_CALLTYPE operator== (
const String& s1, StringRef s2) noexcept {
return s1.getCharPointer().compare (s2.text) == 0; }
568 JUCE_API bool JUCE_CALLTYPE operator!= (
const String& s1, StringRef s2) noexcept {
return s1.getCharPointer().compare (s2.text) != 0; }
569 JUCE_API bool JUCE_CALLTYPE operator== (
const String& s1,
const CharPointer_UTF8 s2) noexcept {
return s1.getCharPointer().compare (s2) == 0; }
570 JUCE_API bool JUCE_CALLTYPE operator!= (
const String& s1,
const CharPointer_UTF8 s2) noexcept {
return s1.getCharPointer().compare (s2) != 0; }
571 JUCE_API bool JUCE_CALLTYPE operator== (
const String& s1,
const CharPointer_UTF16 s2) noexcept {
return s1.getCharPointer().compare (s2) == 0; }
572 JUCE_API bool JUCE_CALLTYPE operator!= (
const String& s1,
const CharPointer_UTF16 s2) noexcept {
return s1.getCharPointer().compare (s2) != 0; }
573 JUCE_API bool JUCE_CALLTYPE operator== (
const String& s1,
const CharPointer_UTF32 s2) noexcept {
return s1.getCharPointer().compare (s2) == 0; }
574 JUCE_API bool JUCE_CALLTYPE operator!= (
const String& s1,
const CharPointer_UTF32 s2) noexcept {
return s1.getCharPointer().compare (s2) != 0; }
575 JUCE_API bool JUCE_CALLTYPE operator> (
const String& s1,
const String& s2) noexcept {
return s1.compare (s2) > 0; }
576 JUCE_API bool JUCE_CALLTYPE operator< (
const String& s1,
const String& s2) noexcept {
return s1.compare (s2) < 0; }
577 JUCE_API bool JUCE_CALLTYPE operator>= (
const String& s1,
const String& s2) noexcept {
return s1.compare (s2) >= 0; }
578 JUCE_API bool JUCE_CALLTYPE operator<= (
const String& s1,
const String& s2) noexcept {
return s1.compare (s2) <= 0; }
582 return t !=
nullptr ? text.compareIgnoreCase (castToCharPointer_wchar_t (t)) == 0
594 return text.compareIgnoreCase (t.text) == 0;
599 return text == other.text
600 || text.compareIgnoreCase (other.text) == 0;
603 int String::compare (
const String& other)
const noexcept {
return (text == other.text) ? 0 : text.compare (other.text); }
605 int String::compare (
const wchar_t*
const other)
const noexcept {
return text.compare (castToCharPointer_wchar_t (other)); }
612 auto c1 = s1.getAndAdvance();
615 auto c2 = s2.getAndAdvance();
618 if (! (isDigit1 || isDigit2))
return bias;
619 if (! isDigit1)
return -1;
620 if (! isDigit2)
return 1;
622 if (c1 != c2 && bias == 0)
623 bias = c1 < c2 ? -1 : 1;
625 jassert (c1 != 0 && c2 != 0);
633 auto c1 = s1.getAndAdvance();
636 auto c2 = s2.getAndAdvance();
639 if (! (isDigit1 || isDigit2))
return 0;
640 if (! isDigit1)
return -1;
641 if (! isDigit2)
return 1;
642 if (c1 < c2)
return -1;
643 if (c1 > c2)
return 1;
649 bool firstLoop =
true;
653 const bool hasSpace1 = s1.isWhitespace();
654 const bool hasSpace2 = s2.isWhitespace();
656 if ((! firstLoop) && (hasSpace1 ^ hasSpace2))
658 if (s1.isEmpty())
return -1;
659 if (s2.isEmpty())
return 1;
661 return hasSpace2 ? 1 : -1;
666 if (hasSpace1) s1 = s1.findEndOfWhitespace();
667 if (hasSpace2) s2 = s2.findEndOfWhitespace();
669 if (s1.isDigit() && s2.isDigit())
671 auto result = (*s1 ==
'0' || *s2 ==
'0') ? stringCompareLeft (s1, s2)
672 : stringCompareRight (s1, s2);
678 auto c1 = s1.getAndAdvance();
679 auto c2 = s2.getAndAdvance();
681 if (c1 != c2 && ! isCaseSensitive)
697 if (isAlphaNum2 && ! isAlphaNum1)
return -1;
698 if (isAlphaNum1 && ! isAlphaNum2)
return 1;
700 return c1 < c2 ? -1 : 1;
703 jassert (c1 != 0 && c2 != 0);
709 return naturalStringCompare (getCharPointer(), other.text, isCaseSensitive);
716 : textToAppend.text, maxCharsToTake);
727 jassert (startOfTextToAppend.
getAddress() !=
nullptr && endOfTextToAppend.
getAddress() !=
nullptr);
729 auto extraBytesNeeded = getAddressDifference (endOfTextToAppend.
getAddress(),
731 jassert (extraBytesNeeded >= 0);
733 if (extraBytesNeeded > 0)
735 auto byteOffsetOfNull = getByteOffsetOfEnd();
738 auto* newStringStart = addBytesToPointer (text.
getAddress(), (
int) byteOffsetOfNull);
739 memcpy (newStringStart, startOfTextToAppend.
getAddress(), (
size_t) extraBytesNeeded);
775 const char asString[] = { ch, 0 };
781 const wchar_t asString[] = { ch, 0 };
785 #if ! JUCE_NATIVE_WCHAR_IS_UTF32
788 const juce_wchar asString[] = { ch, 0 };
794 namespace StringHelpers
796 template <
typename T>
797 inline String& operationAddAssign (String& str,
const T number)
799 char buffer [(
sizeof(T) * 8) / 2];
800 auto* end = buffer + numElementsInArray (buffer);
801 auto* start = NumberToStringConverters::numberToString (end, number);
803 #if JUCE_STRING_UTF_TYPE == 8
806 str.appendCharPointer (CharPointer_ASCII (start), CharPointer_ASCII (end));
819 JUCE_API String JUCE_CALLTYPE operator+ (
const wchar_t* s1,
const String& s2) { String s (s1);
return s += s2; }
824 JUCE_API String JUCE_CALLTYPE operator+ (String s1,
const String& s2) {
return s1 += s2; }
825 JUCE_API String JUCE_CALLTYPE operator+ (String s1,
const char* s2) {
return s1 += s2; }
826 JUCE_API String JUCE_CALLTYPE operator+ (String s1,
const wchar_t* s2) {
return s1 += s2; }
827 JUCE_API String JUCE_CALLTYPE operator+ (String s1,
const std::string& s2) {
return s1 += s2.c_str(); }
829 JUCE_API String JUCE_CALLTYPE operator+ (String s1,
char s2) {
return s1 += s2; }
830 JUCE_API String JUCE_CALLTYPE operator+ (String s1,
wchar_t s2) {
return s1 += s2; }
832 #if ! JUCE_NATIVE_WCHAR_IS_UTF32
834 JUCE_API String JUCE_CALLTYPE operator+ (String s1, juce_wchar s2) {
return s1 += s2; }
835 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, juce_wchar s2) {
return s1 += s2; }
838 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
char s2) {
return s1 += s2; }
839 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
wchar_t s2) {
return s1 += s2; }
841 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
const char* s2) {
return s1 += s2; }
842 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
const wchar_t* s2) {
return s1 += s2; }
843 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
const String& s2) {
return s1 += s2; }
844 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, StringRef s2) {
return s1 += s2; }
845 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
const std::string& s2) {
return s1 += s2.c_str(); }
847 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, uint8 number) {
return s1 += (int) number; }
848 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
short number) {
return s1 += (int) number; }
849 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
int number) {
return s1 += number; }
850 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
long number) {
return s1 += String (number); }
851 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
unsigned long number) {
return s1 += String (number); }
852 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, int64 number) {
return s1 += String (number); }
853 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1, uint64 number) {
return s1 += String (number); }
854 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
float number) {
return s1 += String (number); }
855 JUCE_API String& JUCE_CALLTYPE operator<< (String& s1,
double number) {
return s1 += String (number); }
857 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream,
const String& text)
859 return operator<< (stream, StringRef (text));
862 JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, StringRef text)
866 #if (JUCE_STRING_UTF_TYPE == 8)
867 stream.write (text.text.getAddress(), numBytes);
871 HeapBlock<char> temp (numBytes + 1);
872 CharPointer_UTF8 (temp).writeAll (text.text);
873 stream.write (temp, numBytes);
882 return text.indexOf (character);
889 for (
int i = 0; ! t.isEmpty(); ++i)
893 if (t.getAndAdvance() == character)
910 for (
int i = 0; ! t.isEmpty(); ++i)
911 if (t.getAndAdvance() == character)
921 for (
int i = 0; ! t.isEmpty(); ++i)
925 if (charactersToLookFor.text.indexOf (t.getAndAdvance(), ignoreCase) >= 0)
939 return other.isEmpty() ? 0 : text.indexOf (other.text);
954 for (
int i = startIndex; --i >= 0;)
962 auto found = t.indexOf (other.text);
963 return found >= 0 ? found + startIndex : found;
973 for (
int i = startIndex; --i >= 0;)
982 return found >= 0 ? found + startIndex : found;
987 if (other.isNotEmpty())
989 auto len = other.length();
990 int i = length() - len;
994 for (
auto n = text + i; i >= 0; --i)
996 if (n.compareUpTo (other.text, len) == 0)
1009 if (other.isNotEmpty())
1011 auto len = other.length();
1012 int i = length() - len;
1016 for (
auto n = text + i; i >= 0; --i)
1018 if (n.compareIgnoreCaseUpTo (other.text, len) == 0)
1034 for (
int i = 0; ! t.isEmpty(); ++i)
1035 if (charactersToLookFor.text.indexOf (t.getAndAdvance(), ignoreCase) >= 0)
1043 return indexOf (other) >= 0;
1048 return text.indexOf (character) >= 0;
1053 return indexOfIgnoreCase (t) >= 0;
1058 if (word.isNotEmpty())
1061 auto wordLen = word.length();
1062 auto end = (int) t.length() - wordLen;
1064 for (
int i = 0; i <= end; ++i)
1066 if (t.compareUpTo (word.text, wordLen) == 0
1067 && (i == 0 || ! (t - 1).isLetterOrDigit())
1068 && ! (t + wordLen).isLetterOrDigit())
1080 if (word.isNotEmpty())
1083 auto wordLen = word.length();
1084 auto end = (int) t.length() - wordLen;
1086 for (
int i = 0; i <= end; ++i)
1088 if (t.compareIgnoreCaseUpTo (word.text, wordLen) == 0
1089 && (i == 0 || ! (t - 1).isLetterOrDigit())
1090 && ! (t + wordLen).isLetterOrDigit())
1102 return indexOfWholeWord (wordToLookFor) >= 0;
1107 return indexOfWholeWordIgnoreCase (wordToLookFor) >= 0;
1111 template <
typename CharPo
inter>
1114 static bool matches (CharPointer wildcard, CharPointer test,
const bool ignoreCase) noexcept
1118 auto wc = wildcard.getAndAdvance();
1121 return wildcard.isEmpty() || matchesAnywhere (wildcard, test, ignoreCase);
1123 if (! characterMatches (wc, test.getAndAdvance(), ignoreCase))
1131 static bool characterMatches (
const juce_wchar wc,
const juce_wchar tc,
const bool ignoreCase) noexcept
1133 return (wc == tc) || (wc ==
'?' && tc != 0)
1137 static bool matchesAnywhere (
const CharPointer wildcard, CharPointer test,
const bool ignoreCase) noexcept
1139 for (; ! test.isEmpty(); ++test)
1140 if (matches (wildcard, test, ignoreCase))
1155 if (numberOfTimesToRepeat <= 0)
1158 String result (PreallocationBytes (findByteOffsetOfEnd (stringToRepeat) * (
size_t) numberOfTimesToRepeat));
1159 auto n = result.text;
1161 while (--numberOfTimesToRepeat >= 0)
1169 jassert (padCharacter != 0);
1171 auto extraChars = minimumLength;
1174 while (! end.isEmpty())
1180 if (extraChars <= 0 || padCharacter == 0)
1183 auto currentByteSize = (size_t) (((
char*) end.getAddress()) - (
char*) text.getAddress());
1185 auto n = result.text;
1187 while (--extraChars >= 0)
1188 n.
write (padCharacter);
1196 jassert (padCharacter != 0);
1198 auto extraChars = minimumLength;
1207 if (extraChars <= 0 || padCharacter == 0)
1210 auto currentByteSize = (size_t) (((
char*) end.
getAddress()) - (
char*) text.getAddress());
1212 auto n = result.text;
1216 while (--extraChars >= 0)
1217 n.write (padCharacter);
1233 if (numCharsToReplace < 0)
1236 numCharsToReplace = 0;
1240 auto insertPoint = text;
1242 for (
int i = 0; i < index; ++i)
1244 if (insertPoint.isEmpty())
1248 return *
this + stringToInsert;
1254 auto startOfRemainder = insertPoint;
1256 for (
int i = 0; i < numCharsToReplace && ! startOfRemainder.isEmpty(); ++i)
1259 if (insertPoint == text && startOfRemainder.isEmpty())
1260 return stringToInsert.
text;
1262 auto initialBytes = (size_t) (((
char*) insertPoint.getAddress()) - (
char*) text.getAddress());
1263 auto newStringBytes = findByteOffsetOfEnd (stringToInsert);
1264 auto remainderBytes = (size_t) (((
char*) startOfRemainder.findTerminatingNull().getAddress()) - (
char*) startOfRemainder.getAddress());
1266 auto newTotalBytes = initialBytes + newStringBytes + remainderBytes;
1268 if (newTotalBytes <= 0)
1271 String result (PreallocationBytes ((
size_t) newTotalBytes));
1273 auto* dest = (
char*) result.text.
getAddress();
1274 memcpy (dest, text.getAddress(), initialBytes);
1275 dest += initialBytes;
1277 dest += newStringBytes;
1278 memcpy (dest, startOfRemainder.getAddress(), remainderBytes);
1279 dest += remainderBytes;
1287 auto stringToReplaceLen = stringToReplace.
length();
1288 auto stringToInsertLen = stringToInsert.
length();
1294 : result.
indexOf (i, stringToReplace))) >= 0)
1296 result = result.
replaceSection (i, stringToReplaceLen, stringToInsert);
1297 i += stringToInsertLen;
1305 auto stringToReplaceLen = stringToReplace.
length();
1310 return replaceSection (index, stringToReplaceLen, stringToInsert);
1324 : source (s), allocatedBytes (StringHolder::getAllocatedNumBytes (s))
1330 void write (juce_wchar c)
1334 if (bytesWritten > allocatedBytes)
1336 allocatedBytes += jmax ((
size_t) 8, allocatedBytes / 16);
1347 size_t allocatedBytes, bytesWritten = 0;
1361 if (c == charToReplace)
1370 return std::move (builder.result);
1377 jassert (charactersToReplace.
length() == charactersToInsertInstead.
length());
1384 auto index = charactersToReplace.
text.
indexOf (c);
1387 c = charactersToInsertInstead [index];
1395 return std::move (builder.result);
1401 return text.compareUpTo (other.text, other.length()) == 0;
1406 return text.compareIgnoreCaseUpTo (other.text, other.length()) == 0;
1411 jassert (character != 0);
1413 return *text == character;
1418 jassert (character != 0);
1423 auto t = text.findTerminatingNull();
1424 return *--t == character;
1429 auto end = text.findTerminatingNull();
1430 auto otherEnd = other.text.findTerminatingNull();
1432 while (end > text && otherEnd > other.text)
1437 if (*end != *otherEnd)
1441 return otherEnd == other.text;
1446 auto end = text.findTerminatingNull();
1447 auto otherEnd = other.text.findTerminatingNull();
1449 while (end > text && otherEnd > other.text)
1454 if (end.toLowerCase() != otherEnd.toLowerCase())
1458 return otherEnd == other.text;
1477 return std::move (builder.result);
1495 return std::move (builder.result);
1550 while (--start >= 0)
1563 return String (text, (
size_t) jmax (0,
length() - numberToDrop));
1568 return String (text + jmax (0,
length() - jmax (0, numCharacters)));
1611 static bool isQuoteCharacter (juce_wchar c) noexcept
1613 return c ==
'"' || c ==
'\'';
1618 return isQuoteCharacter (*text.findEndOfWhitespace());
1623 if (! isQuoteCharacter (*text))
1627 return substring (1, len - (isQuoteCharacter (text[len - 1]) ? 1 : 0));
1641 t += quoteCharacter;
1652 if (! (--end).isWhitespace())
1668 auto trimmedEnd = findTrimmedEnd (start, end);
1670 if (trimmedEnd <= start)
1673 if (text < start || trimmedEnd < end)
1674 return String (start, trimmedEnd);
1684 auto t = text.findEndOfWhitespace();
1698 auto trimmedEnd = findTrimmedEnd (text, end);
1700 if (trimmedEnd < end)
1701 return String (text, trimmedEnd);
1714 return t == text ? *this :
String (t);
1722 auto trimmedEnd = end;
1724 while (trimmedEnd > text)
1726 if (charactersToTrim.
text.
indexOf (*--trimmedEnd) < 0)
1733 if (trimmedEnd < end)
1734 return String (text, trimmedEnd);
1760 return std::move (builder.result);
1781 return std::move (builder.result);
1786 for (
auto t = text; ! t.isEmpty(); ++t)
1795 for (
auto t = text; ! t.isEmpty(); ++t)
1804 for (
auto t = text; ! t.isEmpty();)
1805 if (chars.text.indexOf (t.getAndAdvance()) < 0)
1813 for (
auto t = text; ! t.isEmpty();)
1814 if (chars.text.indexOf (t.getAndAdvance()) >= 0)
1822 for (
auto t = text; ! t.isEmpty(); ++t)
1823 if (! t.isWhitespace())
1829 String String::formattedRaw (
const char* pf, ...)
1831 size_t bufferSize = 256;
1836 va_start (args, pf);
1840 int num = (int) vsnprintf (temp.get(), bufferSize - 1, pf, args);
1841 if (num >=
static_cast<int> (bufferSize))
1844 String wideCharVersion (pf);
1846 const int num = (int)
1852 (temp.get(), bufferSize - 1, wideCharVersion.toWideCharPointer(), args);
1857 return String (temp.get());
1861 if (num == 0 || bufferSize > 65536)
1878 auto t = text.findTerminatingNull();
1890 n +=
static_cast<juce_wchar
> (mult) * (*t -
'0');
1897 static const char hexDigits[] =
"0123456789abcdef";
1899 template <
typename Type>
1900 static String hexToString (Type v)
1902 String::CharPointerType::CharType buffer[32];
1903 auto* end = buffer + numElementsInArray (buffer) - 1;
1909 *--t = hexDigits [(int) (v & 15)];
1918 String String::createHex (uint8 n) {
return hexToString (n); }
1919 String String::createHex (uint16 n) {
return hexToString (n); }
1920 String String::createHex (uint32 n) {
return hexToString (n); }
1921 String String::createHex (uint64 n) {
return hexToString (n); }
1928 int numChars = (size * 2) + 2;
1930 numChars += size / groupSize;
1932 String s (PreallocationBytes (
sizeof (CharPointerType::CharType) * (
size_t) numChars));
1934 auto* data =
static_cast<const unsigned char*
> (d);
1937 for (
int i = 0; i < size; ++i)
1939 const unsigned char nextByte = *data++;
1940 dest.
write ((juce_wchar) hexDigits [nextByte >> 4]);
1941 dest.write ((juce_wchar) hexDigits [nextByte & 0xf]);
1943 if (groupSize > 0 && (i % groupSize) == (groupSize - 1) && i < (size - 1))
1944 dest.write ((juce_wchar)
' ');
1955 static String getStringFromWindows1252Codepage (
const char* data,
size_t num)
1959 for (
size_t i = 0; i < num; ++i)
1968 auto* data =
static_cast<const uint8*
> (unknownData);
1970 if (size <= 0 || data ==
nullptr)
1979 const int numChars = size / 2 - 1;
1983 auto src =
reinterpret_cast<const uint16*
> (data + 2);
1987 for (
int i = 0; i < numChars; ++i)
1992 for (
int i = 0; i < numChars; ++i)
1997 return std::move (builder.result);
2000 auto* start = (
const char*) data;
2012 return getStringFromWindows1252Codepage (start, (
size_t) size);
2016 static const juce_wchar emptyChar = 0;
2018 template <
class CharPo
interType_Src,
class CharPo
interType_Dest>
2021 static CharPointerType_Dest convert (
const String& s)
2023 auto& source =
const_cast<String&
> (s);
2025 using DestChar =
typename CharPointerType_Dest::CharType;
2027 if (source.isEmpty())
2028 return CharPointerType_Dest (
reinterpret_cast<const DestChar*
> (&emptyChar));
2030 CharPointerType_Src text (source.getCharPointer());
2031 auto extraBytesNeeded = CharPointerType_Dest::getBytesRequiredFor (text) +
sizeof (
typename CharPointerType_Dest::CharType);
2032 auto endOffset = (text.sizeInBytes() + 3) & ~3u;
2034 source.preallocateBytes (endOffset + extraBytesNeeded);
2035 text = source.getCharPointer();
2037 void*
const newSpace = addBytesToPointer (text.getAddress(), (
int) endOffset);
2038 const CharPointerType_Dest extraSpace (
static_cast<DestChar*
> (newSpace));
2040 #if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..)
2041 auto bytesToClear = (size_t) jmin ((
int) extraBytesNeeded, 4);
2042 zeromem (addBytesToPointer (newSpace, extraBytesNeeded - bytesToClear), bytesToClear);
2045 CharPointerType_Dest (extraSpace).writeAll (text);
2082 std::string String::toStdString()
const
2088 template <
class CharPo
interType_Src,
class CharPo
interType_Dest>
2091 static size_t copyToBuffer (
const CharPointerType_Src source,
typename CharPointerType_Dest::CharType*
const buffer,
const size_t maxBufferSizeBytes)
2093 jassert (((ssize_t) maxBufferSizeBytes) >= 0);
2095 if (buffer ==
nullptr)
2096 return CharPointerType_Dest::getBytesRequiredFor (source) +
sizeof (
typename CharPointerType_Dest::CharType);
2098 return CharPointerType_Dest (buffer).writeWithDestByteLimit (source, maxBufferSizeBytes);
2102 size_t String::copyToUTF8 (CharPointer_UTF8::CharType*
const buffer,
size_t maxBufferSizeBytes)
const noexcept
2107 size_t String::copyToUTF16 (CharPointer_UTF16::CharType*
const buffer,
size_t maxBufferSizeBytes)
const noexcept
2112 size_t String::copyToUTF32 (CharPointer_UTF32::CharType*
const buffer,
size_t maxBufferSizeBytes)
const noexcept
2125 if (buffer !=
nullptr)
2127 if (bufferSizeBytes < 0)
2130 if (bufferSizeBytes > 0)
2141 #pragma warning (pop)
2150 #if JUCE_STRING_UTF_TYPE != 8
2151 : text (
nullptr), stringCopy (stringLiteral)
2153 : text (stringLiteral)
2156 #if JUCE_STRING_UTF_TYPE != 8
2157 text = stringCopy.getCharPointer();
2160 jassert (stringLiteral !=
nullptr);
2162 #if JUCE_NATIVE_WCHAR_IS_UTF8
2182 jassert (stringLiteral.getAddress() !=
nullptr);
2190 static String reduceLengthOfFloatString (
const String& input)
2193 const auto end = start + (int) input.
length();
2194 auto trimStart = end;
2195 auto trimEnd = trimStart;
2196 auto exponentTrimStart = end;
2197 auto exponentTrimEnd = exponentTrimStart;
2199 decltype (*start) currentChar =
'\0';
2201 for (
auto c = end - 1; c > start; --c)
2205 if (currentChar ==
'0' && c + 1 == trimStart)
2209 else if (currentChar ==
'.')
2211 if (trimStart == c + 1 && trimStart != end && *trimStart ==
'0')
2216 else if (currentChar ==
'e' || currentChar ==
'E')
2225 exponentTrimStart = cNext;
2227 if (cNext != end && *cNext ==
'+')
2230 exponentTrimEnd = cNext;
2233 while (cNext != end && *cNext++ ==
'0')
2234 exponentTrimEnd = cNext;
2236 if (exponentTrimEnd == end)
2237 exponentTrimStart = c;
2240 trimEnd = trimStart;
2244 if ((trimStart != trimEnd && currentChar ==
'.') || exponentTrimStart != exponentTrimEnd)
2246 if (trimStart == trimEnd)
2247 return String (start, exponentTrimStart) + String (exponentTrimEnd, end);
2249 if (exponentTrimStart == exponentTrimEnd)
2250 return String (start, trimStart) + String (trimEnd, end);
2252 if (trimEnd == exponentTrimStart)
2253 return String (start, trimStart) + String (exponentTrimEnd, end);
2255 return String (start, trimStart) + String (trimEnd, exponentTrimStart) + String (exponentTrimEnd, end);
2261 static String serialiseDouble (
double input)
2263 auto absInput = std::abs (input);
2265 if (absInput >= 1.0e6 || absInput <= 1.0e-5)
2266 return reduceLengthOfFloatString ({ input, 15,
true });
2268 int intInput = (int) input;
2270 if ((
double) intInput == input)
2271 return { input, 1 };
2273 auto numberOfDecimalPlaces = [absInput]
2277 if (absInput >= 1.0e-3)
2279 if (absInput >= 1.0e-1)
return 16;
2280 if (absInput >= 1.0e-2)
return 17;
2284 if (absInput >= 1.0e-4)
return 19;
2288 if (absInput < 1.0e3)
2290 if (absInput < 1.0e1)
return 15;
2291 if (absInput < 1.0e2)
return 14;
2295 if (absInput < 1.0e4)
return 12;
2296 if (absInput < 1.0e5)
return 11;
2300 return reduceLengthOfFloatString (String (input, numberOfDecimalPlaces));
2307 #define STRINGIFY2(X) #X
2308 #define STRINGIFY(X) STRINGIFY2(X)
2310 class StringTests :
public UnitTest
2313 StringTests() : UnitTest (
"String class",
"Text") {}
2315 template <
class CharPo
interType>
2316 struct TestUTFConversion
2318 static void test (UnitTest& test, Random& r)
2320 String s (createRandomWideCharString (r));
2322 typename CharPointerType::CharType buffer [300];
2324 memset (buffer, 0xff,
sizeof (buffer));
2325 CharPointerType (buffer).writeAll (s.toUTF32());
2326 test.expectEquals (String (CharPointerType (buffer)), s);
2328 memset (buffer, 0xff,
sizeof (buffer));
2329 CharPointerType (buffer).writeAll (s.toUTF16());
2330 test.expectEquals (String (CharPointerType (buffer)), s);
2332 memset (buffer, 0xff,
sizeof (buffer));
2333 CharPointerType (buffer).writeAll (s.toUTF8());
2334 test.expectEquals (String (CharPointerType (buffer)), s);
2336 test.expect (CharPointerType::isValidString (buffer, (
int) strlen ((
const char*) buffer)));
2340 static String createRandomWideCharString (Random& r)
2342 juce_wchar buffer[50] = { 0 };
2344 for (
int i = 0; i < numElementsInArray (buffer) - 1; ++i)
2350 buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
2355 buffer[i] = (juce_wchar) (1 + r.nextInt (0xff));
2358 return CharPointer_UTF32 (buffer);
2361 void runTest()
override
2363 Random r = getRandom();
2366 beginTest (
"Basics");
2368 expect (String().length() == 0);
2369 expect (String() == String());
2370 String s1, s2 (
"abcd");
2371 expect (s1.isEmpty() && ! s1.isNotEmpty());
2372 expect (s2.isNotEmpty() && ! s2.isEmpty());
2373 expect (s2.length() == 4);
2375 expect (s2 == s1 && s1 == s2);
2376 expect (s1 ==
"abcd" && s1 == L
"abcd");
2377 expect (String (
"abcd") == String (L
"abcd"));
2378 expect (String (
"abcdefg", 4) == L
"abcd");
2379 expect (String (
"abcdefg", 4) == String (L
"abcdefg", 4));
2382 expect (s2 +
"e" ==
"abcde" && s2 +
'e' ==
"abcde");
2383 expect (s2 + L
'e' ==
"abcde" && s2 + L
"e" ==
"abcde");
2384 expect (s1.equalsIgnoreCase (
"abcD") && s1 < "abce" && s1 >
"abbb");
2385 expect (s1.startsWith (
"ab") && s1.startsWith (
"abcd") && ! s1.startsWith (
"abcde"));
2386 expect (s1.startsWithIgnoreCase (
"aB") && s1.endsWithIgnoreCase (
"CD"));
2387 expect (s1.endsWith (
"bcd") && ! s1.endsWith (
"aabcd"));
2388 expectEquals (s1.indexOf (String()), 0);
2389 expectEquals (s1.indexOfIgnoreCase (String()), 0);
2390 expect (s1.startsWith (String()) && s1.endsWith (String()) && s1.contains (String()));
2391 expect (s1.contains (
"cd") && s1.contains (
"ab") && s1.contains (
"abcd"));
2392 expect (s1.containsChar (
'a'));
2393 expect (! s1.containsChar (
'x'));
2394 expect (! s1.containsChar (0));
2395 expect (String (
"abc foo bar").containsWholeWord (
"abc") && String (
"abc foo bar").containsWholeWord (
"abc"));
2399 beginTest (
"Operations");
2401 String s (
"012345678");
2402 expect (s.hashCode() != 0);
2403 expect (s.hashCode64() != 0);
2404 expect (s.hashCode() != (s + s).hashCode());
2405 expect (s.hashCode64() != (s + s).hashCode64());
2406 expect (s.compare (String (
"012345678")) == 0);
2407 expect (s.compare (String (
"012345679")) < 0);
2408 expect (s.compare (String (
"012345676")) > 0);
2409 expect (String(
"a").compareNatural (
"A") == 0);
2410 expect (String(
"A").compareNatural (
"B") < 0);
2411 expect (String(
"a").compareNatural (
"B") < 0);
2412 expect (String(
"10").compareNatural (
"2") > 0);
2413 expect (String(
"Abc 10").compareNatural (
"aBC 2") > 0);
2414 expect (String(
"Abc 1").compareNatural (
"aBC 2") < 0);
2417 expect (s.getLastCharacter() == s [s.length() - 1]);
2419 expect (s.substring (0, 3) == L
"012");
2420 expect (s.substring (0, 100) == s);
2421 expect (s.substring (-1, 100) == s);
2422 expect (s.substring (3) ==
"345678");
2423 expect (s.indexOf (String (L
"45")) == 4);
2424 expect (String (
"444445").indexOf (
"45") == 4);
2425 expect (String (
"444445").lastIndexOfChar (
'4') == 4);
2426 expect (String (
"45454545x").lastIndexOf (String (L
"45")) == 6);
2427 expect (String (
"45454545x").lastIndexOfAnyOf (
"456") == 7);
2428 expect (String (
"45454545x").lastIndexOfAnyOf (String (L
"456x")) == 8);
2429 expect (String (
"abABaBaBa").lastIndexOfIgnoreCase (
"aB") == 6);
2430 expect (s.indexOfChar (L
'4') == 4);
2431 expect (s + s ==
"012345678012345678");
2432 expect (s.startsWith (s));
2433 expect (s.startsWith (s.substring (0, 4)));
2434 expect (s.startsWith (s.dropLastCharacters (4)));
2435 expect (s.endsWith (s.substring (5)));
2436 expect (s.endsWith (s));
2437 expect (s.contains (s.substring (3, 6)));
2438 expect (s.contains (s.substring (3)));
2439 expect (s.startsWithChar (s[0]));
2440 expect (s.endsWithChar (s.getLastCharacter()));
2441 expect (s [s.length()] == 0);
2442 expect (String (
"abcdEFGH").toLowerCase() == String (
"abcdefgh"));
2443 expect (String (
"abcdEFGH").toUpperCase() == String (
"ABCDEFGH"));
2445 expect (String (StringRef (
"abc")) ==
"abc");
2446 expect (String (StringRef (
"abc")) == StringRef (
"abc"));
2447 expect (String (
"abc") + StringRef (
"def") ==
"abcdef");
2450 s2 << ((int) 4) << ((short) 5) <<
"678" << L
"9" <<
'0';
2452 expect (s2 ==
"1234567890xyz");
2454 expect (s2 ==
"1234567890xyz123");
2456 expect (s2 ==
"1234567890xyz123123");
2457 s2 << StringRef (
"def");
2458 expect (s2 ==
"1234567890xyz123123def");
2462 String numStr (std::numeric_limits<int16>::max());
2463 expect (numStr ==
"32767");
2466 String numStr (std::numeric_limits<int16>::min());
2467 expect (numStr ==
"-32768");
2471 numStr << std::numeric_limits<int16>::max();
2472 expect (numStr ==
"32767");
2476 numStr << std::numeric_limits<int16>::min();
2477 expect (numStr ==
"-32768");
2481 String numStr (std::numeric_limits<int32>::max());
2482 expect (numStr ==
"2147483647");
2485 String numStr (std::numeric_limits<int32>::min());
2486 expect (numStr ==
"-2147483648");
2490 numStr << std::numeric_limits<int32>::max();
2491 expect (numStr ==
"2147483647");
2495 numStr << std::numeric_limits<int32>::min();
2496 expect (numStr ==
"-2147483648");
2500 String numStr (std::numeric_limits<uint32>::max());
2501 expect (numStr ==
"4294967295");
2504 String numStr (std::numeric_limits<uint32>::min());
2505 expect (numStr ==
"0");
2509 String numStr (std::numeric_limits<int64>::max());
2510 expect (numStr ==
"9223372036854775807");
2513 String numStr (std::numeric_limits<int64>::min());
2514 expect (numStr ==
"-9223372036854775808");
2518 numStr << std::numeric_limits<int64>::max();
2519 expect (numStr ==
"9223372036854775807");
2523 numStr << std::numeric_limits<int64>::min();
2524 expect (numStr ==
"-9223372036854775808");
2528 String numStr (std::numeric_limits<uint64>::max());
2529 expect (numStr ==
"18446744073709551615");
2532 String numStr (std::numeric_limits<uint64>::min());
2533 expect (numStr ==
"0");
2537 numStr << std::numeric_limits<uint64>::max();
2538 expect (numStr ==
"18446744073709551615");
2542 numStr << std::numeric_limits<uint64>::min();
2543 expect (numStr ==
"0");
2547 String numStr (std::numeric_limits<size_t>::min());
2548 expect (numStr ==
"0");
2551 beginTest (
"Numeric conversions");
2552 expect (String().getIntValue() == 0);
2553 expect (String().getDoubleValue() == 0.0);
2554 expect (String().getFloatValue() == 0.0f);
2555 expect (s.getIntValue() == 12345678);
2556 expect (s.getLargeIntValue() == (int64) 12345678);
2557 expect (s.getDoubleValue() == 12345678.0);
2558 expect (s.getFloatValue() == 12345678.0f);
2559 expect (String (-1234).getIntValue() == -1234);
2560 expect (String ((int64) -1234).getLargeIntValue() == -1234);
2561 expect (String (-1234.56).getDoubleValue() == -1234.56);
2562 expect (String (-1234.56f).getFloatValue() == -1234.56f);
2563 expect (String (std::numeric_limits<int>::max()).getIntValue() == std::numeric_limits<int>::max());
2564 expect (String (std::numeric_limits<int>::min()).getIntValue() == std::numeric_limits<int>::min());
2565 expect (String (std::numeric_limits<int64>::max()).getLargeIntValue() == std::numeric_limits<int64>::max());
2566 expect (String (std::numeric_limits<int64>::min()).getLargeIntValue() == std::numeric_limits<int64>::min());
2567 expect ((
"xyz" + s).getTrailingIntValue() == s.getIntValue());
2568 expect (s.getHexValue32() == 0x12345678);
2569 expect (s.getHexValue64() == (int64) 0x12345678);
2580 unsigned char data[] = { 1, 2, 3, 4, 0xa, 0xb, 0xc, 0xd };
2585 expectEquals (String (12345.67, 4), String (
"12345.6700"));
2586 expectEquals (String (12345.67, 6), String (
"12345.670000"));
2587 expectEquals (String (2589410.5894, 7), String (
"2589410.5894000"));
2588 expectEquals (String (12345.67, 8), String (
"12345.67000000"));
2589 expectEquals (String (1e19, 4), String (
"10000000000000000000.0000"));
2590 expectEquals (String (1e-34, 36), String (
"0.000000000000000000000000000000000100"));
2591 expectEquals (String (1.39, 1), String (
"1.4"));
2593 expectEquals (String (12345.67, 4,
true), String (
"1.2346e+04"));
2594 expectEquals (String (12345.67, 6,
true), String (
"1.234567e+04"));
2595 expectEquals (String (2589410.5894, 7,
true), String (
"2.5894106e+06"));
2596 expectEquals (String (12345.67, 8,
true), String (
"1.23456700e+04"));
2597 expectEquals (String (1e19, 4,
true), String (
"1.0000e+19"));
2598 expectEquals (String (1e-34, 5,
true), String (
"1.00000e-34"));
2599 expectEquals (String (1.39, 1,
true), String (
"1.4e+00"));
2601 beginTest (
"Subsections");
2604 expect (s3.equalsIgnoreCase (
"ABCdeFGhiJ"));
2605 expect (s3.compareIgnoreCase (L
"ABCdeFGhiJ") == 0);
2606 expect (s3.containsIgnoreCase (s3.substring (3)));
2607 expect (s3.indexOfAnyOf (
"xyzf", 2,
true) == 5);
2608 expect (s3.indexOfAnyOf (String (L
"xyzf"), 2,
false) == -1);
2609 expect (s3.indexOfAnyOf (
"xyzF", 2,
false) == 5);
2610 expect (s3.containsAnyOf (String (L
"zzzFs")));
2611 expect (s3.startsWith (
"abcd"));
2612 expect (s3.startsWithIgnoreCase (String (L
"abCD")));
2613 expect (s3.startsWith (String()));
2614 expect (s3.startsWithChar (
'a'));
2615 expect (s3.endsWith (String (
"HIJ")));
2616 expect (s3.endsWithIgnoreCase (String (L
"Hij")));
2617 expect (s3.endsWith (String()));
2618 expect (s3.endsWithChar (L
'J'));
2619 expect (s3.indexOf (
"HIJ") == 7);
2620 expect (s3.indexOf (String (L
"HIJK")) == -1);
2621 expect (s3.indexOfIgnoreCase (
"hij") == 7);
2622 expect (s3.indexOfIgnoreCase (String (L
"hijk")) == -1);
2623 expect (s3.toStdString() == s3.toRawUTF8());
2626 s4.append (String (
"xyz123"), 3);
2627 expect (s4 == s3 +
"xyz");
2629 expect (String (1234) < String (1235));
2630 expect (String (1235) > String (1234));
2631 expect (String (1234) >= String (1234));
2632 expect (String (1234) <= String (1234));
2633 expect (String (1235) >= String (1234));
2634 expect (String (1234) <= String (1235));
2636 String s5 (
"word word2 word3");
2637 expect (s5.containsWholeWord (String (
"word2")));
2638 expect (s5.indexOfWholeWord (
"word2") == 5);
2639 expect (s5.containsWholeWord (String (L
"word")));
2640 expect (s5.containsWholeWord (
"word3"));
2641 expect (s5.containsWholeWord (s5));
2642 expect (s5.containsWholeWordIgnoreCase (String (L
"Word2")));
2643 expect (s5.indexOfWholeWordIgnoreCase (
"Word2") == 5);
2644 expect (s5.containsWholeWordIgnoreCase (String (L
"Word")));
2645 expect (s5.containsWholeWordIgnoreCase (
"Word3"));
2646 expect (! s5.containsWholeWordIgnoreCase (String (L
"Wordx")));
2647 expect (! s5.containsWholeWordIgnoreCase (
"xWord2"));
2648 expect (s5.containsNonWhitespaceChars());
2649 expect (s5.containsOnly (
"ordw23 "));
2650 expect (! String (
" \n\r\t").containsNonWhitespaceChars());
2652 expect (s5.matchesWildcard (String (L
"wor*"),
false));
2653 expect (s5.matchesWildcard (
"wOr*",
true));
2654 expect (s5.matchesWildcard (String (L
"*word3"),
true));
2655 expect (s5.matchesWildcard (
"*word?",
true));
2656 expect (s5.matchesWildcard (String (L
"Word*3"),
true));
2657 expect (! s5.matchesWildcard (String (L
"*34"),
true));
2658 expect (String (
"xx**y").matchesWildcard (
"*y",
true));
2659 expect (String (
"xx**y").matchesWildcard (
"x*y",
true));
2660 expect (String (
"xx**y").matchesWildcard (
"xx*y",
true));
2661 expect (String (
"xx**y").matchesWildcard (
"xx*",
true));
2662 expect (String (
"xx?y").matchesWildcard (
"x??y",
true));
2663 expect (String (
"xx?y").matchesWildcard (
"xx?y",
true));
2664 expect (! String (
"xx?y").matchesWildcard (
"xx?y?",
true));
2665 expect (String (
"xx?y").matchesWildcard (
"xx??",
true));
2667 expectEquals (s5.fromFirstOccurrenceOf (String(),
true,
false), s5);
2668 expectEquals (s5.fromFirstOccurrenceOf (
"xword2",
true,
false), s5.substring (100));
2669 expectEquals (s5.fromFirstOccurrenceOf (String (L
"word2"),
true,
false), s5.substring (5));
2670 expectEquals (s5.fromFirstOccurrenceOf (
"Word2",
true,
true), s5.substring (5));
2671 expectEquals (s5.fromFirstOccurrenceOf (
"word2",
false,
false), s5.getLastCharacters (6));
2672 expectEquals (s5.fromFirstOccurrenceOf (
"Word2",
false,
true), s5.getLastCharacters (6));
2674 expectEquals (s5.fromLastOccurrenceOf (String(),
true,
false), s5);
2675 expectEquals (s5.fromLastOccurrenceOf (
"wordx",
true,
false), s5);
2676 expectEquals (s5.fromLastOccurrenceOf (
"word",
true,
false), s5.getLastCharacters (5));
2677 expectEquals (s5.fromLastOccurrenceOf (
"worD",
true,
true), s5.getLastCharacters (5));
2678 expectEquals (s5.fromLastOccurrenceOf (
"word",
false,
false), s5.getLastCharacters (1));
2679 expectEquals (s5.fromLastOccurrenceOf (
"worD",
false,
true), s5.getLastCharacters (1));
2681 expect (s5.upToFirstOccurrenceOf (String(),
true,
false).isEmpty());
2682 expectEquals (s5.upToFirstOccurrenceOf (
"word4",
true,
false), s5);
2683 expectEquals (s5.upToFirstOccurrenceOf (
"word2",
true,
false), s5.substring (0, 10));
2684 expectEquals (s5.upToFirstOccurrenceOf (
"Word2",
true,
true), s5.substring (0, 10));
2685 expectEquals (s5.upToFirstOccurrenceOf (
"word2",
false,
false), s5.substring (0, 5));
2686 expectEquals (s5.upToFirstOccurrenceOf (
"Word2",
false,
true), s5.substring (0, 5));
2688 expectEquals (s5.upToLastOccurrenceOf (String(),
true,
false), s5);
2689 expectEquals (s5.upToLastOccurrenceOf (
"zword",
true,
false), s5);
2690 expectEquals (s5.upToLastOccurrenceOf (
"word",
true,
false), s5.dropLastCharacters (1));
2691 expectEquals (s5.dropLastCharacters(1).upToLastOccurrenceOf (
"word",
true,
false), s5.dropLastCharacters (1));
2692 expectEquals (s5.upToLastOccurrenceOf (
"Word",
true,
true), s5.dropLastCharacters (1));
2693 expectEquals (s5.upToLastOccurrenceOf (
"word",
false,
false), s5.dropLastCharacters (5));
2694 expectEquals (s5.upToLastOccurrenceOf (
"Word",
false,
true), s5.dropLastCharacters (5));
2696 expectEquals (s5.replace (
"word",
"xyz",
false), String (
"xyz xyz2 xyz3"));
2697 expect (s5.replace (
"Word",
"xyz",
true) ==
"xyz xyz2 xyz3");
2698 expect (s5.dropLastCharacters (1).replace (
"Word", String (
"xyz"),
true) == L
"xyz xyz2 xyz");
2699 expect (s5.replace (
"Word",
"",
true) ==
" 2 3");
2700 expectEquals (s5.replace (
"Word2",
"xyz",
true), String (
"word xyz word3"));
2701 expect (s5.replaceCharacter (L
'w',
'x') != s5);
2702 expectEquals (s5.replaceCharacter (
'w', L
'x').replaceCharacter (
'x',
'w'), s5);
2703 expect (s5.replaceCharacters (
"wo",
"xy") != s5);
2704 expectEquals (s5.replaceCharacters (
"wo",
"xy").replaceCharacters (
"xy",
"wo"), s5);
2705 expectEquals (s5.retainCharacters (
"1wordxya"), String (
"wordwordword"));
2706 expect (s5.retainCharacters (String()).isEmpty());
2707 expect (s5.removeCharacters (
"1wordxya") ==
" 2 3");
2708 expectEquals (s5.removeCharacters (String()), s5);
2709 expect (s5.initialSectionContainingOnly (
"word") == L
"word");
2710 expect (String (
"word").initialSectionContainingOnly (
"word") == L
"word");
2711 expectEquals (s5.initialSectionNotContaining (String (
"xyz ")), String (
"word"));
2712 expectEquals (s5.initialSectionNotContaining (String (
";[:'/")), s5);
2713 expect (! s5.isQuotedString());
2714 expect (s5.quoted().isQuotedString());
2715 expect (! s5.quoted().unquoted().isQuotedString());
2716 expect (! String (
"x'").isQuotedString());
2717 expect (String (
"'x").isQuotedString());
2719 String s6 (
" \t xyz \t\r\n");
2720 expectEquals (s6.trim(), String (
"xyz"));
2721 expect (s6.trim().trim() ==
"xyz");
2722 expectEquals (s5.trim(), s5);
2723 expectEquals (s6.trimStart().trimEnd(), s6.trim());
2724 expectEquals (s6.trimStart().trimEnd(), s6.trimEnd().trimStart());
2725 expectEquals (s6.trimStart().trimStart().trimEnd().trimEnd(), s6.trimEnd().trimStart());
2726 expect (s6.trimStart() != s6.trimEnd());
2727 expectEquals ((
"\t\r\n " + s6 +
"\t\n \r").trim(), s6.trim());
2732 beginTest (
"UTF conversions");
2734 TestUTFConversion <CharPointer_UTF32>::test (*
this, r);
2735 TestUTFConversion <CharPointer_UTF8>::test (*
this, r);
2736 TestUTFConversion <CharPointer_UTF16>::test (*
this, r);
2740 beginTest (
"StringArray");
2743 s.addTokens (
"4,3,2,1,0",
";,",
"x");
2744 expectEquals (s.size(), 5);
2746 expectEquals (s.joinIntoString (
"-"), String (
"4-3-2-1-0"));
2748 expectEquals (s.joinIntoString (
"--"), String (
"4--3--1--0"));
2749 expectEquals (s.joinIntoString (StringRef()), String (
"4310"));
2751 expectEquals (s.joinIntoString (
"x"), String());
2754 toks.addTokens (
"x,,",
";,",
"");
2755 expectEquals (toks.size(), 3);
2756 expectEquals (toks.joinIntoString (
"-"), String (
"x--"));
2759 toks.addTokens (
",x,",
";,",
"");
2760 expectEquals (toks.size(), 3);
2761 expectEquals (toks.joinIntoString (
"-"), String (
"-x-"));
2764 toks.addTokens (
"x,'y,z',",
";,",
"'");
2765 expectEquals (toks.size(), 3);
2766 expectEquals (toks.joinIntoString (
"-"), String (
"x-'y,z'-"));
2777 expect (! v2.equals (v1));
2778 expect (! v1.equals (v2));
2779 expect (v2.equals (v3));
2780 expect (! v3.equals (v1));
2781 expect (! v1.equals (v3));
2782 expect (v1.equals (v4));
2783 expect (v4.equals (v1));
2784 expect (v5.equals (v4));
2785 expect (v4.equals (v5));
2786 expect (! v2.equals (v4));
2787 expect (! v4.equals (v2));
2791 beginTest (
"Significant figures");
2834 beginTest (
"Float trimming");
2837 StringPairArray tests;
2838 tests.set (
"1",
"1");
2839 tests.set (
"1.0",
"1.0");
2840 tests.set (
"-1",
"-1");
2841 tests.set (
"-100",
"-100");
2842 tests.set (
"110",
"110");
2843 tests.set (
"9090",
"9090");
2844 tests.set (
"1000.0",
"1000.0");
2845 tests.set (
"1.0",
"1.0");
2846 tests.set (
"-1.00",
"-1.0");
2847 tests.set (
"1.20",
"1.2");
2848 tests.set (
"1.300",
"1.3");
2849 tests.set (
"1.301",
"1.301");
2850 tests.set (
"1e",
"1");
2851 tests.set (
"-1e+",
"-1");
2852 tests.set (
"1e-",
"1");
2853 tests.set (
"1e0",
"1");
2854 tests.set (
"1e+0",
"1");
2855 tests.set (
"1e-0",
"1");
2856 tests.set (
"1e000",
"1");
2857 tests.set (
"1e+000",
"1");
2858 tests.set (
"-1e-000",
"-1");
2859 tests.set (
"1e100",
"1e100");
2860 tests.set (
"100e100",
"100e100");
2861 tests.set (
"100.0e0100",
"100.0e100");
2862 tests.set (
"-1e1",
"-1e1");
2863 tests.set (
"1e10",
"1e10");
2864 tests.set (
"-1e+10",
"-1e10");
2865 tests.set (
"1e-10",
"1e-10");
2866 tests.set (
"1e0010",
"1e10");
2867 tests.set (
"1e-0010",
"1e-10");
2868 tests.set (
"1e-1",
"1e-1");
2869 tests.set (
"-1.0e1",
"-1.0e1");
2870 tests.set (
"1.0e-1",
"1.0e-1");
2871 tests.set (
"1.00e-1",
"1.0e-1");
2872 tests.set (
"1.001e1",
"1.001e1");
2873 tests.set (
"1.010e+1",
"1.01e1");
2874 tests.set (
"-1.1000e1",
"-1.1e1");
2876 for (
auto& input : tests.getAllKeys())
2877 expectEquals (reduceLengthOfFloatString (input), tests[input]);
2881 std::map<double, String> tests;
2884 tests[1.01] =
"1.01";
2885 tests[0.76378] =
"7.6378e-1";
2886 tests[-10] =
"-1.0e1";
2887 tests[10.01] =
"1.001e1";
2888 tests[10691.01] =
"1.069101e4";
2889 tests[0.0123] =
"1.23e-2";
2890 tests[-3.7e-27] =
"-3.7e-27";
2891 tests[1e+40] =
"1.0e40";
2893 for (
auto& test : tests)
2894 expectEquals (reduceLengthOfFloatString (String (test.first, 15,
true)), test.second);
2899 beginTest (
"Serialisation");
2901 std::map <double, String> tests;
2903 tests[364] =
"364.0";
2904 tests[1e7] =
"1.0e7";
2905 tests[12345678901] =
"1.2345678901e10";
2907 tests[1234567890123456.7] =
"1.234567890123457e15";
2908 tests[12345678.901234567] =
"1.234567890123457e7";
2909 tests[1234567.8901234567] =
"1.234567890123457e6";
2910 tests[123456.78901234567] =
"123456.7890123457";
2911 tests[12345.678901234567] =
"12345.67890123457";
2912 tests[1234.5678901234567] =
"1234.567890123457";
2913 tests[123.45678901234567] =
"123.4567890123457";
2914 tests[12.345678901234567] =
"12.34567890123457";
2915 tests[1.2345678901234567] =
"1.234567890123457";
2916 tests[0.12345678901234567] =
"0.1234567890123457";
2917 tests[0.012345678901234567] =
"0.01234567890123457";
2918 tests[0.0012345678901234567] =
"0.001234567890123457";
2919 tests[0.00012345678901234567] =
"0.0001234567890123457";
2920 tests[0.000012345678901234567] =
"0.00001234567890123457";
2921 tests[0.0000012345678901234567] =
"1.234567890123457e-6";
2922 tests[0.00000012345678901234567] =
"1.234567890123457e-7";
2924 for (
auto& test : tests)
2926 expectEquals (serialiseDouble (test.first), test.second);
2927 expectEquals (serialiseDouble (-test.first),
"-" + test.second);
2933 static StringTests stringUnitTests;