Skip to content

Commit

Permalink
Merge pull request #12225 from KratosMultiphysics/core/string-utils-trim
Browse files Browse the repository at this point in the history
[Core][StringUtils] add trimming functions
  • Loading branch information
philbucher authored Apr 21, 2024
2 parents 4f36915 + a7a2401 commit 508f68d
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 27 deletions.
124 changes: 104 additions & 20 deletions kratos/tests/cpp_tests/utilities/test_string_utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
// Kratos default license: kratos/license.txt
//
// Main authors: Vicente Mataix Ferrandiz
//
// Philipp Bucher (https://github.com/philbucher)
//

// System includes
#include <tuple>

// External includes

// Project includes
#include "testing/testing.h"
#include "utilities/string_utilities.h"

namespace Kratos {
namespace Testing {
namespace Kratos::Testing {

KRATOS_TEST_CASE_IN_SUITE(ConvertCamelCaseToSnakeCase, KratosCoreFastSuite)
{
Expand Down Expand Up @@ -62,21 +62,22 @@ KRATOS_TEST_CASE_IN_SUITE(ConvertSnakeCaseToCamelCase, KratosCoreFastSuite)
} \
catch (...) {}

KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("Test"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("tesT"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("te__st"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("__te_st"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("test__"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("te st"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase(" test"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("test "))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("*nullptr"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("core/stringutils"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("c-s"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("-cs"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("cs-"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("ph@"))
KRATOS_EXPECT_THROWS(StringUtilities::ConvertSnakeCaseToCamelCase("#include"))
// deliberately ignoring [[nodiscard]] as it is not relevant for this test
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("Test"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("tesT"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("te__st"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("__te_st"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("test__"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("te st"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase(" test"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("test "))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("*nullptr"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("core/stringutils"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("c-s"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("-cs"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("cs-"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("ph@"))
KRATOS_EXPECT_THROWS(std::ignore = StringUtilities::ConvertSnakeCaseToCamelCase("#include"))

#undef KRATOS_EXPECT_THROWS
}
Expand Down Expand Up @@ -129,5 +130,88 @@ KRATOS_TEST_CASE_IN_SUITE(ReplaceAllSubstrings, KratosCoreFastSuite)
KRATOS_EXPECT_EQ(correct_string, "JoJo Bizarre Adventure is an awesome show. JoJo Bizarre Adventure is the best!");
}

} // namespace Testing
} // namespace Kratos.
KRATOS_TEST_CASE_IN_SUITE(Trim, KratosCoreFastSuite)
{
using namespace std::string_literals; // required for strings with null-chars => "asdf\0"s

KRATOS_EXPECT_EQ(StringUtilities::Trim(""), "");
KRATOS_EXPECT_EQ(StringUtilities::Trim(" "), "");
KRATOS_EXPECT_EQ(StringUtilities::Trim("\n"), "");
KRATOS_EXPECT_EQ(StringUtilities::Trim("\t"), "");
KRATOS_EXPECT_EQ(StringUtilities::Trim("\0"), "\0");
KRATOS_EXPECT_EQ(StringUtilities::Trim("\0", true), "");

KRATOS_EXPECT_EQ(StringUtilities::Trim("Kratos"), "Kratos");
KRATOS_EXPECT_EQ(StringUtilities::Trim(" Kratos "), "Kratos");
KRATOS_EXPECT_EQ(StringUtilities::Trim(" Kra tos "), "Kra tos");
KRATOS_EXPECT_EQ(StringUtilities::Trim(" Kra\0tos "), "Kra\0tos");
KRATOS_EXPECT_EQ(StringUtilities::Trim(" Kra\ntos "), "Kra\ntos");
KRATOS_EXPECT_EQ(StringUtilities::Trim(" \0 Kra\ntos \0 "s), "\0 Kra\ntos \0"s);
KRATOS_EXPECT_EQ(StringUtilities::Trim(" \0 Kra\ntos \0 "s, true), "Kra\ntos");

KRATOS_EXPECT_EQ(StringUtilities::Trim("Kratos MP"), "Kratos MP");
KRATOS_EXPECT_EQ(StringUtilities::Trim(" Kratos MP "), "Kratos MP");
KRATOS_EXPECT_EQ(StringUtilities::Trim("\tKratos MP\n"), "Kratos MP");
KRATOS_EXPECT_EQ(StringUtilities::Trim(" Kra tos MP "), "Kra tos MP");
KRATOS_EXPECT_EQ(StringUtilities::Trim(" Kra\0tos MP "), "Kra\0tos MP");
KRATOS_EXPECT_EQ(StringUtilities::Trim(" Kra\ntos MP "), "Kra\ntos MP");
}

KRATOS_TEST_CASE_IN_SUITE(TrimLeft, KratosCoreFastSuite)
{
using namespace std::string_literals; // required for strings with null-chars => "asdf\0"s

KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(""), "");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" "), "");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft("\n"), "");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft("\t"), "");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft("\0"), "\0");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft("\0", true), "");

KRATOS_EXPECT_EQ(StringUtilities::TrimLeft("Kratos"), "Kratos");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" Kratos "), "Kratos ");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" Kra tos "), "Kra tos ");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" Kra\0tos "), "Kra\0tos ");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" Kra\ntos "), "Kra\ntos ");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" Kra\ntos\0"s), "Kra\ntos\0"s);
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" \0 Kra\ntos \0 "s), "\0 Kra\ntos \0 "s);
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" \0 Kra\ntos \0 "s, true), "Kra\ntos \0 "s);

KRATOS_EXPECT_EQ(StringUtilities::TrimLeft("Kratos MP"), "Kratos MP");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" Kratos MP "), "Kratos MP ");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft("\tKratos MP\n"), "Kratos MP\n");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" Kra tos MP "), "Kra tos MP ");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" Kra\0tos MP "), "Kra\0tos MP ");
KRATOS_EXPECT_EQ(StringUtilities::TrimLeft(" Kra\ntos MP "), "Kra\ntos MP ");
}

KRATOS_TEST_CASE_IN_SUITE(TrimRight, KratosCoreFastSuite)
{
using namespace std::string_literals; // required for strings with null-chars => "asdf\0"s

KRATOS_EXPECT_EQ(StringUtilities::TrimRight(""), "");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" "), "");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight("\n"), "");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight("\t"), "");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight("\0"), "\0");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight("\0", true), "");

KRATOS_EXPECT_EQ(StringUtilities::TrimRight("Kratos"), "Kratos");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" Kratos "), " Kratos");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" Kra tos "), " Kra tos");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" Kra\0tos "), " Kra\0tos");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" Kra\ntos "), " Kra\ntos");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" Kra\ntos\0"s), " Kra\ntos\0"s);
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" Kra\ntos\0"s, true), " Kra\ntos");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" \0 Kra\ntos \0 "s), " \0 Kra\ntos \0"s);
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" \0 Kra\ntos \0 "s, true), " \0 Kra\ntos"s);

KRATOS_EXPECT_EQ(StringUtilities::TrimRight("Kratos MP"), "Kratos MP");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" Kratos MP "), " Kratos MP");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight("\tKratos MP\n"), "\tKratos MP");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" Kra tos MP "), " Kra tos MP");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" Kra\0tos MP "), " Kra\0tos MP");
KRATOS_EXPECT_EQ(StringUtilities::TrimRight(" Kra\ntos MP "), " Kra\ntos MP");
}

} // namespace Kratos::Testing
51 changes: 51 additions & 0 deletions kratos/utilities/string_utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,55 @@ std::string ReplaceAllSubstrings(
return output_string;
}

std::string Trim(
const std::string& rInputString,
const bool RemoveNullChar)
{
return TrimLeft(TrimRight(rInputString, RemoveNullChar), RemoveNullChar);
}

std::function<bool(std::string::value_type)> TrimChar(const bool RemoveNullChar)
{
if (RemoveNullChar) {
return [](auto character) {
return std::isspace(character) || character == '\0';
};
}

return [](auto character) {
return std::isspace(character);
};
}

std::string TrimLeft(
const std::string& rInputString,
const bool RemoveNullChar)
{
std::string output_string(rInputString);

const auto trim_char = TrimChar(RemoveNullChar);

output_string.erase(output_string.begin(), std::find_if(output_string.begin(), output_string.end(),
[trim_char](std::string::value_type ch) {return !trim_char(ch);}
)
);

return output_string;
}

std::string TrimRight(
const std::string& rInputString,
const bool RemoveNullChar)
{
std::string output_string(rInputString);
const auto trim_char = TrimChar(RemoveNullChar);

output_string.erase(std::find_if(output_string.rbegin(), output_string.rend(),
[trim_char](std::string::value_type ch) {return !trim_char(ch);}
).base(), output_string.end()
);

return output_string;
}

} // namespace Kratos::StringUtilities
46 changes: 39 additions & 7 deletions kratos/utilities/string_utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// Kratos default license: kratos/license.txt
//
// Main authors: Vicente Mataix Ferrandiz
// Philipp Bucher (https://github.com/philbucher)
//

#pragma once
Expand Down Expand Up @@ -54,7 +55,7 @@ namespace StringUtilities
* @param rString The string to be transformed into snake_case
* @return The string in snake_case
*/
std::string KRATOS_API(KRATOS_CORE) ConvertCamelCaseToSnakeCase(const std::string& rString);
[[nodiscard]] std::string KRATOS_API(KRATOS_CORE) ConvertCamelCaseToSnakeCase(const std::string& rString);

/**
* @brief Convert snake_case to CamelCase.
Expand All @@ -64,15 +65,15 @@ namespace StringUtilities
* - contains special characters other than underscores (?![a-z0-9_])
* - contains repeated underscores __+
*/
std::string KRATOS_API(KRATOS_CORE) ConvertSnakeCaseToCamelCase(const std::string& rString);
[[nodiscard]] std::string KRATOS_API(KRATOS_CORE) ConvertSnakeCaseToCamelCase(const std::string& rString);

/**
* @brief Erase first occurrence of given substring from main string.
* @param rMainString The string to be transformed
* @param rToErase The string to remove
* @return The string without the part to remove
*/
std::string KRATOS_API(KRATOS_CORE) ErasePartialString(
[[nodiscard]] std::string KRATOS_API(KRATOS_CORE) ErasePartialString(
const std::string& rMainString,
const std::string& rToErase
);
Expand All @@ -83,7 +84,7 @@ namespace StringUtilities
* @param rToCheck The string to search
* @return True if the substring is found and false otherwise
*/
bool KRATOS_API(KRATOS_CORE) ContainsPartialString(
[[nodiscard]] bool KRATOS_API(KRATOS_CORE) ContainsPartialString(
const std::string& rMainString,
const std::string& rToCheck
);
Expand All @@ -93,15 +94,15 @@ namespace StringUtilities
* @param rString The string to be transformed
* @return The string without white spaces
*/
std::string KRATOS_API(KRATOS_CORE) RemoveWhiteSpaces(const std::string& rString);
[[nodiscard]] std::string KRATOS_API(KRATOS_CORE) RemoveWhiteSpaces(const std::string& rString);

/**
* @brief This method splits a string by a delimiter
* @param rString The string to be splitted
* @param Delimiter The delimiter by which the string is to be splitted
* @return a vector containing the splitted string
*/
std::vector<std::string> KRATOS_API(KRATOS_CORE) SplitStringByDelimiter(
[[nodiscard]] std::vector<std::string> KRATOS_API(KRATOS_CORE) SplitStringByDelimiter(
const std::string& rString,
const char Delimiter
);
Expand All @@ -113,12 +114,43 @@ namespace StringUtilities
* @param rStringToReplace The string which replaces the substring
* @return The string updated with the new substring
*/
std::string KRATOS_API(KRATOS_CORE) ReplaceAllSubstrings(
[[nodiscard]] std::string KRATOS_API(KRATOS_CORE) ReplaceAllSubstrings(
const std::string& rInputString,
const std::string& rStringToBeReplaced,
const std::string& rStringToReplace
);

/**
* @brief This function trims a string by removing whitespaces, tabs etc from left and right. Same as "strip" in Python
* @param rInputString The input string to trim
* @param RemoveNullChar Whether or not null-characters ('\0') should be removed
* @return The trimmed string
*/
[[nodiscard]] std::string KRATOS_API(KRATOS_CORE) Trim(
const std::string& rInputString,
const bool RemoveNullChar = false);

/**
* @brief This function trims a string by removing whitespaces, tabs etc from left. Same as "lstrip" in Python
* @param rInputString The input string to trim
* @param RemoveNullChar Whether or not null-characters ('\0') should be removed
* @return The trimmed string
*/
[[nodiscard]] std::string KRATOS_API(KRATOS_CORE) TrimLeft(
const std::string& rInputString,
const bool RemoveNullChar = false);

/**
* @brief This function trims a string by removing whitespaces, tabs etc and right. Same as "rstrip" in Python
* @param rInputString The input string to trim
* @param RemoveNullChar Whether or not null-characters ('\0') should be removed
* @return The trimmed string
*/
[[nodiscard]] std::string KRATOS_API(KRATOS_CORE) TrimRight(
const std::string& rInputString,
const bool RemoveNullChar = false);


/**
* @brief Prints the data of an object of type TClass to the given output stream with indentation.
* @param rOStream The output stream where the data will be printed.
Expand Down

0 comments on commit 508f68d

Please sign in to comment.