Improve interface for string operations

Trim incoming string before converting to number
Remove use of std::strtod and std::stoi
Use std::string_view instead of std::string when possible
This commit is contained in:
Magne Sjaastad
2024-07-25 21:21:53 +02:00
parent 33ffa10ec9
commit 6fb74654a1
9 changed files with 108 additions and 46 deletions
@@ -32,7 +32,7 @@ const std::string WHITESPACE = " \n\r\t\f\v";
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
std::string RiaStdStringTools::leftTrimString( const std::string& s ) std::string_view RiaStdStringTools::leftTrimString( std::string_view s )
{ {
size_t start = s.find_first_not_of( WHITESPACE ); size_t start = s.find_first_not_of( WHITESPACE );
return ( start == std::string::npos ) ? "" : s.substr( start ); return ( start == std::string::npos ) ? "" : s.substr( start );
@@ -41,7 +41,7 @@ std::string RiaStdStringTools::leftTrimString( const std::string& s )
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
std::string RiaStdStringTools::rightTrimString( const std::string& s ) std::string_view RiaStdStringTools::rightTrimString( std::string_view s )
{ {
size_t end = s.find_last_not_of( WHITESPACE ); size_t end = s.find_last_not_of( WHITESPACE );
return ( end == std::string::npos ) ? "" : s.substr( 0, end + 1 ); return ( end == std::string::npos ) ? "" : s.substr( 0, end + 1 );
@@ -50,7 +50,7 @@ std::string RiaStdStringTools::rightTrimString( const std::string& s )
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
std::string RiaStdStringTools::trimString( const std::string& s ) std::string_view RiaStdStringTools::trimString( std::string_view s )
{ {
return rightTrimString( leftTrimString( s ) ); return rightTrimString( leftTrimString( s ) );
} }
@@ -87,42 +87,24 @@ bool RiaStdStringTools::isNumber( const std::string& s, char decimalPoint )
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
int16_t RiaStdStringTools::toInt16( const std::string& s ) int16_t RiaStdStringTools::toInt16( std::string_view s )
{ {
return (int16_t)toInt( s ); return (int16_t)toInt( s );
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// /// Convert a string to an integer. If the string is not a valid integer, the function returns -1.
/// For best performance, use toInt( const std::string_view& s, int& value );
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
int RiaStdStringTools::toInt( const std::string& s ) int RiaStdStringTools::toInt( std::string_view s )
{ {
int intValue = -1; int intValue = -1;
try toInt( s, intValue );
{
intValue = std::stoi( s );
}
catch ( ... )
{
}
return intValue; return intValue;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RiaStdStringTools::toDouble( const std::string& s )
{
double doubleValue = -1.0;
char* end;
doubleValue = std::strtod( s.data(), &end );
return doubleValue;
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -164,8 +146,11 @@ std::string RiaStdStringTools::formatThousandGrouping( long value )
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
bool RiaStdStringTools::toDouble( const std::string_view& s, double& value ) bool RiaStdStringTools::toDouble( std::string_view s, double& value )
{ {
s.remove_prefix( std::min( s.find_first_not_of( " " ), s.size() ) );
// NB! Note that we use fast_float:: here, and not std::
auto resultObject = fast_float::from_chars( s.data(), s.data() + s.size(), value ); auto resultObject = fast_float::from_chars( s.data(), s.data() + s.size(), value );
return ( resultObject.ec == std::errc() ); return ( resultObject.ec == std::errc() );
@@ -174,8 +159,10 @@ bool RiaStdStringTools::toDouble( const std::string_view& s, double& value )
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
bool RiaStdStringTools::toInt( const std::string_view& s, int& value ) bool RiaStdStringTools::toInt( std::string_view s, int& value )
{ {
s.remove_prefix( std::min( s.find_first_not_of( " " ), s.size() ) );
auto resultObject = std::from_chars( s.data(), s.data() + s.size(), value ); auto resultObject = std::from_chars( s.data(), s.data() + s.size(), value );
return ( resultObject.ec == std::errc() ); return ( resultObject.ec == std::errc() );
@@ -184,9 +171,9 @@ bool RiaStdStringTools::toInt( const std::string_view& s, int& value )
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
std::string RiaStdStringTools::toUpper( const std::string& s ) std::string RiaStdStringTools::toUpper( std::string_view s )
{ {
auto strCopy( s ); std::string strCopy( s );
std::transform( strCopy.begin(), strCopy.end(), strCopy.begin(), []( unsigned char c ) { return std::toupper( c ); } ); std::transform( strCopy.begin(), strCopy.end(), strCopy.begin(), []( unsigned char c ) { return std::toupper( c ); } );
return strCopy; return strCopy;
@@ -31,26 +31,25 @@
class RiaStdStringTools class RiaStdStringTools
{ {
public: public:
static std::string trimString( const std::string& s ); static std::string_view trimString( std::string_view s );
static std::string rightTrimString( const std::string& s ); static std::string_view rightTrimString( std::string_view s );
static std::string leftTrimString( const std::string& s ); static std::string_view leftTrimString( std::string_view s );
static std::string removeWhitespace( const std::string& line ); static std::string removeWhitespace( const std::string& line );
static bool isNumber( const std::string& s, char decimalPoint ); static bool isNumber( const std::string& s, char decimalPoint );
static int16_t toInt16( const std::string& s ); static int16_t toInt16( std::string_view s );
static int toInt( const std::string& s ); static int toInt( std::string_view s );
static double toDouble( const std::string& s );
static bool containsAlphabetic( const std::string& s ); static bool containsAlphabetic( const std::string& s );
static bool startsWithAlphabetic( const std::string& s ); static bool startsWithAlphabetic( const std::string& s );
static std::string formatThousandGrouping( long value ); static std::string formatThousandGrouping( long value );
// Conversion using fastest known approach // Conversion using fastest known approach
static bool toDouble( const std::string_view& s, double& value ); static bool toDouble( std::string_view s, double& value );
static bool toInt( const std::string_view& s, int& value ); static bool toInt( std::string_view s, int& value );
static std::string toUpper( const std::string& s ); static std::string toUpper( std::string_view s );
static bool endsWith( const std::string& mainStr, const std::string& toMatch ); static bool endsWith( const std::string& mainStr, const std::string& toMatch );
@@ -228,7 +228,8 @@ bool RifEclipseUserDataParserTools::hasOnlyValidDoubleValues( const std::vector<
} }
else else
{ {
double doubleVal = RiaStdStringTools::toDouble( word ); double doubleVal = 0.0;
RiaStdStringTools::toDouble( word, doubleVal );
doubleValues->push_back( doubleVal ); doubleValues->push_back( doubleVal );
} }
} }
@@ -89,9 +89,11 @@ void RifKeywordVectorParser::parseData( const QString& data )
keywordBasedVector.header = RifEclipseUserDataParserTools::headerReader( streamData, line ); keywordBasedVector.header = RifEclipseUserDataParserTools::headerReader( streamData, line );
if ( keywordBasedVector.header.empty() ) break; if ( keywordBasedVector.header.empty() ) break;
double value = 0.0;
while ( RifEclipseUserDataParserTools::isANumber( line ) ) while ( RifEclipseUserDataParserTools::isANumber( line ) )
{ {
keywordBasedVector.values.push_back( RiaStdStringTools::toDouble( line ) ); RiaStdStringTools::toDouble( line, value );
keywordBasedVector.values.push_back( value );
std::getline( streamData, line ); std::getline( streamData, line );
} }
@@ -217,7 +217,7 @@ std::string RifOpmCommonEclipseSummary::unitName( const RifEclipseSummaryAddress
} }
} }
return RiaStdStringTools::trimString( nameString ); return std::string( RiaStdStringTools::trimString( nameString ) );
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -125,7 +125,7 @@ std::string RifOpmHdf5Summary::unitName( const RifEclipseSummaryAddress& resultA
auto keyword = it->second; auto keyword = it->second;
auto stringFromFileReader = m_eSmry->get_unit( keyword ); auto stringFromFileReader = m_eSmry->get_unit( keyword );
return RiaStdStringTools::trimString( stringFromFileReader ); return std::string( RiaStdStringTools::trimString( stringFromFileReader ) );
} }
} }
@@ -452,7 +452,7 @@ std::vector<size_t> RifInpReader::readElementSet( std::istream& stream )
auto parts = RiaStdStringTools::splitString( line, ',' ); auto parts = RiaStdStringTools::splitString( line, ',' );
for ( auto part : parts ) for ( auto part : parts )
{ {
std::string trimmedPart = RiaStdStringTools::trimString( part ); auto trimmedPart = RiaStdStringTools::trimString( part );
if ( !trimmedPart.empty() ) if ( !trimmedPart.empty() )
{ {
@@ -61,7 +61,8 @@ public:
{ {
if ( input.isEmpty() ) return State::Intermediate; if ( input.isEmpty() ) return State::Intermediate;
double val = RiaStdStringTools::toDouble( input.toStdString() ); double val = 0.0;
RiaStdStringTools::toDouble( input.toStdString(), val );
if ( val > 0.001 && val <= 2.0 ) if ( val > 0.001 && val <= 2.0 )
return State::Acceptable; return State::Acceptable;
else else
@@ -257,3 +257,75 @@ TEST( RiaStdStringToolsTest, TestInvalidRangeStrings )
ASSERT_EQ( expectedValues, actualValues ); ASSERT_EQ( expectedValues, actualValues );
} }
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStdStringToolsTest, TestToDouble )
{
{
std::string text = " 0.123";
double resultValue = 0.0;
auto isOk = RiaStdStringTools::toDouble( text, resultValue );
EXPECT_TRUE( isOk );
EXPECT_DOUBLE_EQ( resultValue, 0.123 );
}
{
std::string text = " 0.123 2";
double resultValue = 0.0;
auto isOk = RiaStdStringTools::toDouble( text, resultValue );
EXPECT_TRUE( isOk );
EXPECT_DOUBLE_EQ( resultValue, 0.123 );
}
{
std::string text = "0.123 2";
double resultValue = 0.0;
auto isOk = RiaStdStringTools::toDouble( text, resultValue );
EXPECT_TRUE( isOk );
EXPECT_DOUBLE_EQ( resultValue, 0.123 );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStdStringToolsTest, TestToInt )
{
{
std::string text = " 12";
int resultValue = -1;
auto isOk = RiaStdStringTools::toInt( text, resultValue );
EXPECT_TRUE( isOk );
EXPECT_EQ( resultValue, 12 );
}
{
std::string text = " 12 ";
int resultValue = -1;
auto isOk = RiaStdStringTools::toInt( text, resultValue );
EXPECT_TRUE( isOk );
EXPECT_EQ( resultValue, 12 );
}
{
std::string text = "12";
int resultValue = -1;
auto isOk = RiaStdStringTools::toInt( text, resultValue );
EXPECT_TRUE( isOk );
EXPECT_EQ( resultValue, 12 );
}
}