Skip to content

Commit 7e5f5e4

Browse files
litelawlietAdrien Givry
andauthored
Added function to trim leading/trailing whitespaces (#372)
* Added function to trim leading/trailing whitespaces Trim static method added in OvTools::String and uses an enum for the trim type/direction. Added internal helpers to perform the leading or trailing trim. * Update Sources/Overload/OvTools/src/OvTools/Utils/String.cpp Co-authored-by: Adrien Givry <services@adrien-givry.com> * Update Sources/Overload/OvTools/src/OvTools/Utils/String.cpp Co-authored-by: Adrien Givry <services@adrien-givry.com> * Update Trim method to C++20 manipulations * Fix format --------- Co-authored-by: Adrien Givry <services@adrien-givry.com>
1 parent 4a8356c commit 7e5f5e4

3 files changed

Lines changed: 80 additions & 55 deletions

File tree

Sources/Overload/OvTools/include/OvTools/Utils/String.h

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,17 @@
1313
namespace OvTools::Utils
1414
{
1515
/*
16-
* Handle random numbers generation
16+
* Helper class for string manipulation
1717
*/
1818
class String
1919
{
2020
public:
21+
struct TrimOptions
22+
{
23+
const bool left = true;
24+
const bool right = true;
25+
};
26+
2127
/**
2228
* Disabled constructor
2329
*/
@@ -39,11 +45,18 @@ namespace OvTools::Utils
3945
*/
4046
static void ReplaceAll(std::string& p_target, const std::string& p_from, const std::string& p_to);
4147

42-
/**
43-
* Generate a unique string satisfying the availability predicate
44-
* @param p_source
45-
* @param p_isAvailable (A callback that must returning true if the input string is available)
46-
*/
47-
static std::string GenerateUnique(const std::string& p_source, std::function<bool(std::string)> p_isAvailable);
48+
/**
49+
* Generate a unique string satisfying the availability predicate
50+
* @param p_source
51+
* @param p_isAvailable (A callback that must returning true if the input string is available)
52+
*/
53+
static std::string GenerateUnique(const std::string& p_source, std::function<bool(std::string)> p_isAvailable);
54+
55+
/**
56+
* Trim whitespaces from a string with the option to trim the left and right of the string by passing a TrimOptions struct.
57+
* @param p_str String to trim
58+
* @param p_trimOptions The desired trim options, default is trimming left and right
59+
*/
60+
static void Trim(std::string& p_str, const TrimOptions p_trimOptions = {});
4861
};
49-
}
62+
}

Sources/Overload/OvTools/src/OvTools/Filesystem/IniFile.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
*/
66

77
#include "OvTools/Filesystem/IniFile.h"
8+
#include "OvTools/Utils/String.h"
89

9-
#include <filesystem>
1010
#include <fstream>
1111

1212
OvTools::Filesystem::IniFile::IniFile(const std::string& p_filePath) : m_filePath(p_filePath)
@@ -74,7 +74,7 @@ void OvTools::Filesystem::IniFile::Load()
7474
{
7575
if (IsValidLine(currentLine))
7676
{
77-
currentLine.erase(std::remove_if(currentLine.begin(), currentLine.end(), isspace), currentLine.end());
77+
OvTools::Utils::String::Trim(currentLine);
7878
RegisterPair(ExtractKeyAndValue(currentLine));
7979
}
8080
}
@@ -132,4 +132,4 @@ bool OvTools::Filesystem::IniFile::IsValidLine(const std::string & p_attributeLi
132132
bool OvTools::Filesystem::IniFile::StringToBoolean(const std::string & p_value) const
133133
{
134134
return (p_value == "1" || p_value == "T" || p_value == "t" || p_value == "True" || p_value == "true");
135-
}
135+
}

Sources/Overload/OvTools/src/OvTools/Utils/String.cpp

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -33,48 +33,60 @@ void OvTools::Utils::String::ReplaceAll(std::string& p_target, const std::string
3333

3434
std::string OvTools::Utils::String::GenerateUnique(const std::string& p_source, std::function<bool(std::string)> p_isAvailable)
3535
{
36-
auto suffixlessSource = p_source;
37-
38-
auto suffixOpeningParenthesisPos = std::string::npos;
39-
auto suffixClosingParenthesisPos = std::string::npos;
40-
41-
// Keep track of the current character position when iterating onto `p_source`
42-
auto currentPos = decltype(std::string::npos){p_source.length() - 1};
43-
44-
// Here we search for `(` and `)` positions. (Needed to extract the number between those parenthesis)
45-
for (auto it = p_source.rbegin(); it < p_source.rend(); ++it, --currentPos)
46-
{
47-
const auto c = *it;
48-
49-
if (suffixClosingParenthesisPos == std::string::npos && c == ')') suffixClosingParenthesisPos = currentPos;
50-
if (suffixClosingParenthesisPos != std::string::npos && c == '(') suffixOpeningParenthesisPos = currentPos;
51-
}
52-
53-
// We need to declare our `counter` here to store the number between found parenthesis OR 1 (In the case no parenthesis, AKA, suffix, has been found)
54-
auto counter = uint32_t{ 1 };
55-
56-
// If the two parenthis have been found AND the closing parenthesis is the last character AND there is a space before the opening parenthesis
57-
if (suffixOpeningParenthesisPos != std::string::npos && suffixClosingParenthesisPos == p_source.length() - 1 && suffixOpeningParenthesisPos > 0 && p_source[suffixOpeningParenthesisPos - 1] == ' ')
58-
{
59-
// Extract the string between those parenthesis
60-
const auto between = p_source.substr(suffixOpeningParenthesisPos + 1, suffixClosingParenthesisPos - suffixOpeningParenthesisPos - 1);
61-
62-
// If the `between` string is composed of digits (AKA, `between` is a number)
63-
if (!between.empty() && std::find_if(between.begin(), between.end(), [](unsigned char c) { return !std::isdigit(c); }) == between.end())
64-
{
65-
counter = static_cast<uint32_t>(std::atoi(between.c_str()));
66-
suffixlessSource = p_source.substr(0, suffixOpeningParenthesisPos - 1);
67-
}
68-
}
69-
70-
auto result = suffixlessSource;
71-
72-
// While `result` isn't available, we keep generating new strings
73-
while (!p_isAvailable(result))
74-
{
75-
// New strings are composed of the `suffixlessSource` (Ex: "Foo (1)" without suffix is "Foo")
76-
result = suffixlessSource + " (" + std::to_string(counter++) + ")";
77-
}
78-
79-
return result;
36+
auto suffixlessSource = p_source;
37+
38+
auto suffixOpeningParenthesisPos = std::string::npos;
39+
auto suffixClosingParenthesisPos = std::string::npos;
40+
41+
// Keep track of the current character position when iterating onto `p_source`
42+
auto currentPos = decltype(std::string::npos){p_source.length() - 1};
43+
44+
// Here we search for `(` and `)` positions. (Needed to extract the number between those parenthesis)
45+
for (auto it = p_source.rbegin(); it < p_source.rend(); ++it, --currentPos)
46+
{
47+
const auto c = *it;
48+
49+
if (suffixClosingParenthesisPos == std::string::npos && c == ')') suffixClosingParenthesisPos = currentPos;
50+
if (suffixClosingParenthesisPos != std::string::npos && c == '(') suffixOpeningParenthesisPos = currentPos;
51+
}
52+
53+
// We need to declare our `counter` here to store the number between found parenthesis OR 1 (In the case no parenthesis, AKA, suffix, has been found)
54+
auto counter = uint32_t{ 1 };
55+
56+
// If the two parenthis have been found AND the closing parenthesis is the last character AND there is a space before the opening parenthesis
57+
if (suffixOpeningParenthesisPos != std::string::npos && suffixClosingParenthesisPos == p_source.length() - 1 && suffixOpeningParenthesisPos > 0 && p_source[suffixOpeningParenthesisPos - 1] == ' ')
58+
{
59+
// Extract the string between those parenthesis
60+
const auto between = p_source.substr(suffixOpeningParenthesisPos + 1, suffixClosingParenthesisPos - suffixOpeningParenthesisPos - 1);
61+
62+
// If the `between` string is composed of digits (AKA, `between` is a number)
63+
if (!between.empty() && std::find_if(between.begin(), between.end(), [](unsigned char c) { return !std::isdigit(c); }) == between.end())
64+
{
65+
counter = static_cast<uint32_t>(std::atoi(between.c_str()));
66+
suffixlessSource = p_source.substr(0, suffixOpeningParenthesisPos - 1);
67+
}
68+
}
69+
70+
auto result = suffixlessSource;
71+
72+
// While `result` isn't available, we keep generating new strings
73+
while (!p_isAvailable(result))
74+
{
75+
// New strings are composed of the `suffixlessSource` (Ex: "Foo (1)" without suffix is "Foo")
76+
result = suffixlessSource + " (" + std::to_string(counter++) + ")";
77+
}
78+
79+
return result;
80+
}
81+
82+
void OvTools::Utils::String::Trim(std::string& p_str, const TrimOptions p_trimOptions)
83+
{
84+
if (p_trimOptions.left)
85+
{
86+
p_str.erase(0, p_str.find_first_not_of(" \t\n\r\f\v"));
87+
}
88+
if (p_trimOptions.right)
89+
{
90+
p_str.erase(p_str.find_last_not_of(" \t\n\r\f\v") + 1);
91+
}
8092
}

0 commit comments

Comments
 (0)