mirror of
https://github.com/OPM/ResInsight.git
synced 2026-08-27 05:37:21 -05:00
Improves string trimming and parsing
Refactors string trimming functions for improved performance by using a lookup table for whitespace characters. Also adds a function to split a string into two tokens at the first whitespace.
This commit is contained in:
@@ -23,19 +23,55 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <array>
|
||||
#include <charconv>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
|
||||
const std::string WHITESPACE = " \n\r\t\f\v";
|
||||
// Lookup table for fast whitespace checking
|
||||
// Using array of 256 elements (all possible char values)
|
||||
// where true means the character is whitespace
|
||||
namespace
|
||||
{
|
||||
// Create a compile-time whitespace lookup table
|
||||
constexpr std::array<bool, 256> createWhitespaceTable()
|
||||
{
|
||||
std::array<bool, 256> table = {}; // Initialize all to false
|
||||
|
||||
// Mark standard whitespace characters as true
|
||||
table[' '] = true; // space
|
||||
table['\n'] = true; // newline
|
||||
table['\r'] = true; // carriage return
|
||||
table['\t'] = true; // tab
|
||||
table['\f'] = true; // form feed
|
||||
table['\v'] = true; // vertical tab
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
// Create the lookup table at compile time
|
||||
constexpr auto WHITESPACE_TABLE = createWhitespaceTable();
|
||||
|
||||
// Helper function to check if a character is whitespace
|
||||
constexpr bool isWhitespace( unsigned char c )
|
||||
{
|
||||
return WHITESPACE_TABLE[c];
|
||||
}
|
||||
} // namespace
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string_view RiaStdStringTools::leftTrimString( std::string_view s )
|
||||
{
|
||||
size_t start = s.find_first_not_of( WHITESPACE );
|
||||
return ( start == std::string::npos ) ? "" : s.substr( start );
|
||||
const char* data = s.data();
|
||||
const char* end = data + s.size();
|
||||
|
||||
// Find first non-whitespace character
|
||||
while ( data < end && isWhitespace( static_cast<unsigned char>( *data ) ) )
|
||||
++data;
|
||||
|
||||
return std::string_view( data, end - data );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -43,8 +79,14 @@ std::string_view RiaStdStringTools::leftTrimString( std::string_view s )
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
std::string_view RiaStdStringTools::rightTrimString( std::string_view s )
|
||||
{
|
||||
size_t end = s.find_last_not_of( WHITESPACE );
|
||||
return ( end == std::string::npos ) ? "" : s.substr( 0, end + 1 );
|
||||
const char* data = s.data();
|
||||
const char* end = data + s.size();
|
||||
|
||||
// Find last non-whitespace character
|
||||
while ( end > data && isWhitespace( static_cast<unsigned char>( *( end - 1 ) ) ) )
|
||||
--end;
|
||||
|
||||
return std::string_view( data, end - data );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
@@ -68,7 +110,17 @@ std::string RiaStdStringTools::removeWhitespace( const std::string& line )
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaStdStringTools::isNumber( const std::string& s, char decimalPoint )
|
||||
char RiaStdStringTools::decimalPoint()
|
||||
{
|
||||
std::locale loc;
|
||||
char decimalPoint = std::use_facet<std::numpunct<char>>( loc ).decimal_point();
|
||||
return decimalPoint;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool RiaStdStringTools::isNumber( std::string_view s, char decimalPoint )
|
||||
{
|
||||
if ( s.empty() ) return false;
|
||||
if ( findCharMatchCount( s, decimalPoint ) > 1 ) return false;
|
||||
@@ -222,7 +274,42 @@ std::string RiaStdStringTools::joinStrings( const std::vector<std::string>& s, c
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RiaStdStringTools::findCharMatchCount( const std::string& s, char c )
|
||||
std::pair<std::string_view, std::string_view> RiaStdStringTools::splitAtWhitespace( std::string_view str )
|
||||
{
|
||||
const char* data = str.data();
|
||||
const char* end = data + str.size();
|
||||
const char* pos = data;
|
||||
|
||||
// Skip leading whitespace
|
||||
while ( pos < end && isWhitespace( static_cast<unsigned char>( *pos ) ) )
|
||||
++pos;
|
||||
|
||||
// Beginning of first token
|
||||
const char* firstStart = pos;
|
||||
|
||||
// Find end of first token (first whitespace character)
|
||||
while ( pos < end && !isWhitespace( static_cast<unsigned char>( *pos ) ) )
|
||||
++pos;
|
||||
|
||||
if ( pos >= end ) return {};
|
||||
|
||||
std::string_view first( firstStart, pos - firstStart );
|
||||
|
||||
// Skip all whitespace characters
|
||||
while ( pos < end && isWhitespace( static_cast<unsigned char>( *pos ) ) )
|
||||
++pos;
|
||||
|
||||
if ( pos >= end ) return { first, {} };
|
||||
|
||||
std::string_view second( pos, end - pos );
|
||||
|
||||
return { first, rightTrimString( second ) };
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
size_t RiaStdStringTools::findCharMatchCount( std::string_view s, char c )
|
||||
{
|
||||
size_t count = 0;
|
||||
size_t pos = 0;
|
||||
|
||||
@@ -36,7 +36,8 @@ public:
|
||||
static std::string_view leftTrimString( std::string_view s );
|
||||
static std::string removeWhitespace( const std::string& line );
|
||||
|
||||
static bool isNumber( const std::string& s, char decimalPoint );
|
||||
static char decimalPoint();
|
||||
static bool isNumber( std::string_view s, char decimalPoint );
|
||||
|
||||
static int16_t toInt16( std::string_view s );
|
||||
static int toInt( std::string_view s );
|
||||
@@ -56,6 +57,8 @@ public:
|
||||
static std::vector<std::string> splitString( const std::string& s, char delimiter );
|
||||
static std::string joinStrings( const std::vector<std::string>& s, char delimiter );
|
||||
|
||||
static std::pair<std::string_view, std::string_view> splitAtWhitespace( std::string_view str );
|
||||
|
||||
static int computeEditDistance( const std::string& x, const std::string& y );
|
||||
|
||||
static std::string removeHtmlTags( const std::string& s );
|
||||
@@ -75,7 +78,7 @@ public:
|
||||
private:
|
||||
template <class Container>
|
||||
static void splitByDelimiter( const std::string& str, Container& cont, char delimiter = ' ' );
|
||||
static size_t findCharMatchCount( const std::string& s, char c );
|
||||
static size_t findCharMatchCount( std::string_view s, char c );
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
@@ -95,6 +95,7 @@ TEST( RiaStdStringToolsTest, LeftTrimString )
|
||||
std::make_pair( "\tbla\v", "bla\v" ),
|
||||
std::make_pair( "bla", "bla" ),
|
||||
std::make_pair( "", "" ),
|
||||
std::make_pair( "\t\t\t\t\t\t\t\t", "" ),
|
||||
};
|
||||
|
||||
for ( auto [input, expectedText] : testData )
|
||||
@@ -117,6 +118,7 @@ TEST( RiaStdStringToolsTest, RightTrimString )
|
||||
std::make_pair( "\tbla\v", "\tbla" ),
|
||||
std::make_pair( "bla", "bla" ),
|
||||
std::make_pair( "", "" ),
|
||||
std::make_pair( "\t\t\t\t\t\t\t\t", "" ),
|
||||
};
|
||||
|
||||
for ( auto [input, expectedText] : testData )
|
||||
@@ -139,6 +141,8 @@ TEST( RiaStdStringToolsTest, RemoveWhitespace )
|
||||
std::make_pair( "\tbla\v", "bla" ),
|
||||
std::make_pair( "bla", "bla" ),
|
||||
std::make_pair( "", "" ),
|
||||
std::make_pair( "\t\t\t\t\t\t\t\t", "" ),
|
||||
|
||||
};
|
||||
|
||||
for ( auto [input, expectedText] : testData )
|
||||
@@ -147,6 +151,29 @@ TEST( RiaStdStringToolsTest, RemoveWhitespace )
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RiaStdStringToolsTest, StringInTwoTokens )
|
||||
{
|
||||
std::vector<std::pair<std::string, std::pair<std::string, std::string>>> testData = {
|
||||
std::make_pair( "bla bla", std::make_pair( "bla", "bla" ) ),
|
||||
std::make_pair( "bla bla", std::make_pair( "bla", "bla" ) ),
|
||||
std::make_pair( " bla bla ", std::make_pair( "bla", "bla" ) ),
|
||||
std::make_pair( "\tbla\tbla\t", std::make_pair( "bla", "bla" ) ),
|
||||
std::make_pair( "\tbla\v bla\v", std::make_pair( "bla", "bla" ) ),
|
||||
std::make_pair( "", std::make_pair( "", "" ) ),
|
||||
std::make_pair( "\t\t\t\t\t\t\t\t", std::make_pair( "", "" ) ),
|
||||
};
|
||||
|
||||
for ( auto [input, expectedText] : testData )
|
||||
{
|
||||
const auto& [first, second] = RiaStdStringTools::splitAtWhitespace( input );
|
||||
EXPECT_EQ( first, expectedText.first );
|
||||
EXPECT_EQ( second, expectedText.second );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user