Fixed bugs in String and StringView functions (Replace, Compare, etc.).

This commit is contained in:
Zbigniew Skowron
2021-08-15 14:25:47 +02:00
parent 741714cd61
commit 49524d7418
3 changed files with 31 additions and 23 deletions

View File

@@ -226,7 +226,9 @@ bool String::IsANSI() const
bool String::StartsWith(const StringView& prefix, StringSearchCase searchCase) const
{
if (prefix.IsEmpty() || prefix.Length() > Length())
if (prefix.IsEmpty())
return true;
if (prefix.Length() > Length())
return false;
if (searchCase == StringSearchCase::IgnoreCase)
return !StringUtils::CompareIgnoreCase(this->GetText(), *prefix, prefix.Length());
@@ -235,7 +237,9 @@ bool String::StartsWith(const StringView& prefix, StringSearchCase searchCase) c
bool String::EndsWith(const StringView& suffix, StringSearchCase searchCase) const
{
if (suffix.IsEmpty() || suffix.Length() > Length())
if (suffix.IsEmpty())
return true;
if (suffix.Length() > Length())
return false;
if (searchCase == StringSearchCase::IgnoreCase)
return !StringUtils::CompareIgnoreCase(&(*this)[Length() - suffix.Length()], *suffix);

View File

@@ -65,10 +65,11 @@ public:
/// <summary>
/// Lexicographically tests how this string compares to the other given string.
/// In case sensitive mode 'A' is less than 'a'.
/// </summary>
/// <param name="str">The another string test against.</param>
/// <param name="searchCase">The case sensitivity mode.</param>
/// <returns>0 if equal, -1 if less than, 1 if greater than.</returns>
/// <returns>0 if equal, negative number if less than, positive number if greater than.</returns>
int32 Compare(const StringBase& str, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
if (searchCase == StringSearchCase::CaseSensitive)
@@ -352,7 +353,7 @@ public:
bool StartsWith(T c, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
const int32 length = Length();
if (searchCase == StringSearchCase::IgnoreCase)
if (searchCase == StringSearchCase::CaseSensitive)
return length > 0 && _data[0] == c;
return length > 0 && StringUtils::ToLower(_data[0]) == StringUtils::ToLower(c);
}
@@ -360,14 +361,16 @@ public:
bool EndsWith(T c, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
const int32 length = Length();
if (searchCase == StringSearchCase::IgnoreCase)
if (searchCase == StringSearchCase::CaseSensitive)
return length > 0 && _data[length - 1] == c;
return length > 0 && StringUtils::ToLower(_data[length - 1]) == StringUtils::ToLower(c);
}
bool StartsWith(const StringBase& prefix, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
if (prefix.IsEmpty() || Length() < prefix.Length())
if (prefix.IsEmpty())
return true;
if (Length() < prefix.Length())
return false;
if (searchCase == StringSearchCase::IgnoreCase)
return StringUtils::CompareIgnoreCase(this->GetText(), *prefix, prefix.Length()) == 0;
@@ -376,7 +379,9 @@ public:
bool EndsWith(const StringBase& suffix, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
if (suffix.IsEmpty() || Length() < suffix.Length())
if (suffix.IsEmpty())
return true;
if (Length() < suffix.Length())
return false;
if (searchCase == StringSearchCase::IgnoreCase)
return StringUtils::CompareIgnoreCase(&(*this)[Length() - suffix.Length()], *suffix) == 0;
@@ -429,22 +434,19 @@ public:
/// <summary>
/// Replaces all occurences of searchText within current string with replacementText.
/// </summary>
/// <param name="searchText">String to search for. If empty or null no replacements are done.</param>
/// <param name="searchTextLength">Length of searchText.</param>
/// <param name="searchText">String to search for.</param>
/// <param name="searchTextLength">Length of searchText. Must be greater than zero.</param>
/// <param name="replacementText">String to replace with. Null is treated as empty string.</param>
/// <param name="replacementTextLength">Length of replacementText.</param>
/// <returns>Number of replacements made. (In case-sensitive mode if search text and replacement text are equal no replacements are done, and zero is returned.)</returns>
/// <returns>Number of replacements made (in other words number of occurences of searchText).</returns>
int32 Replace(const T* searchText, int32 searchTextLength, const T* replacementText, int32 replacementTextLength, StringSearchCase searchCase = StringSearchCase::CaseSensitive)
{
if (!HasChars())
return 0;
if (searchTextLength == 0)
return 0;
// If we are doing case sensitive search and replacement text is equal to search text, we do nothing.
if ((searchCase == StringSearchCase::CaseSensitive) && (searchTextLength == replacementTextLength) && (StringUtils::Compare(searchText, replacementText) == 0))
{
ASSERT(false); // Empty search text never makes sense, and is always sign of a bug in calling code.
return 0;
}

View File

@@ -54,21 +54,23 @@ public:
/// <summary>
/// Lexicographically tests how this string compares to the other given string.
/// In case sensitive mode 'A' is less than 'a'.
/// </summary>
/// <param name="str">The another string test against.</param>
/// <param name="searchCase">The case sensitivity mode.</param>
/// <returns>0 if equal, -1 if less than, 1 if greater than.</returns>
/// <returns>0 if equal, negative number if less than, positive number if greater than.</returns>
int32 Compare(const StringViewBase& str, StringSearchCase searchCase = StringSearchCase::CaseSensitive) const
{
const int32 lengthDiff = Length() - str.Length();
if (lengthDiff != 0)
return lengthDiff;
if (Length() == 0)
const bool thisIsShorter = Length() < str.Length();
const int32 minLength = thisIsShorter ? Length() : str.Length();
const int32 prefixCompare = (searchCase == StringSearchCase::CaseSensitive)
? StringUtils::Compare(this->GetNonTerminatedText(), str.GetNonTerminatedText(), minLength)
: StringUtils::CompareIgnoreCase(this->GetNonTerminatedText(), str.GetNonTerminatedText(), minLength);
if (prefixCompare != 0)
return prefixCompare;
if (Length() == str.Length())
return 0;
// We know here that both this StringView and str are not empty, and therefore Get() below are valid.
if (searchCase == StringSearchCase::CaseSensitive)
return StringUtils::Compare(this->Get(), str.Get(), Length());
return StringUtils::CompareIgnoreCase(this->Get(), str.Get(), Length());
return thisIsShorter ? -1 : 1;
}
public: