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 20:11:49 +02:00
parent 33ffa10ec9
commit 6fb74654a1
9 changed files with 108 additions and 46 deletions

View File

@ -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 );
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 );
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 ) );
}
@ -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 );
}
//--------------------------------------------------------------------------------------------------
///
/// 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;
try
{
intValue = std::stoi( s );
}
catch ( ... )
{
}
toInt( s, 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 );
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 );
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 ); } );
return strCopy;

View File

@ -31,26 +31,25 @@
class RiaStdStringTools
{
public:
static std::string trimString( const std::string& s );
static std::string rightTrimString( const std::string& s );
static std::string leftTrimString( const std::string& s );
static std::string removeWhitespace( const std::string& line );
static std::string_view trimString( std::string_view s );
static std::string_view rightTrimString( std::string_view s );
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 int16_t toInt16( const std::string& s );
static int toInt( const std::string& s );
static double toDouble( const std::string& s );
static int16_t toInt16( std::string_view s );
static int toInt( std::string_view s );
static bool containsAlphabetic( const std::string& s );
static bool startsWithAlphabetic( const std::string& s );
static std::string formatThousandGrouping( long value );
// Conversion using fastest known approach
static bool toDouble( const std::string_view& s, double& value );
static bool toInt( const std::string_view& s, int& value );
static bool toDouble( std::string_view s, double& 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 );

View File

@ -228,7 +228,8 @@ bool RifEclipseUserDataParserTools::hasOnlyValidDoubleValues( const std::vector<
}
else
{
double doubleVal = RiaStdStringTools::toDouble( word );
double doubleVal = 0.0;
RiaStdStringTools::toDouble( word, doubleVal );
doubleValues->push_back( doubleVal );
}
}

View File

@ -89,9 +89,11 @@ void RifKeywordVectorParser::parseData( const QString& data )
keywordBasedVector.header = RifEclipseUserDataParserTools::headerReader( streamData, line );
if ( keywordBasedVector.header.empty() ) break;
double value = 0.0;
while ( RifEclipseUserDataParserTools::isANumber( line ) )
{
keywordBasedVector.values.push_back( RiaStdStringTools::toDouble( line ) );
RiaStdStringTools::toDouble( line, value );
keywordBasedVector.values.push_back( value );
std::getline( streamData, line );
}

View File

@ -217,7 +217,7 @@ std::string RifOpmCommonEclipseSummary::unitName( const RifEclipseSummaryAddress
}
}
return RiaStdStringTools::trimString( nameString );
return std::string( RiaStdStringTools::trimString( nameString ) );
}
//--------------------------------------------------------------------------------------------------

View File

@ -125,7 +125,7 @@ std::string RifOpmHdf5Summary::unitName( const RifEclipseSummaryAddress& resultA
auto keyword = it->second;
auto stringFromFileReader = m_eSmry->get_unit( keyword );
return RiaStdStringTools::trimString( stringFromFileReader );
return std::string( RiaStdStringTools::trimString( stringFromFileReader ) );
}
}

View File

@ -452,7 +452,7 @@ std::vector<size_t> RifInpReader::readElementSet( std::istream& stream )
auto parts = RiaStdStringTools::splitString( line, ',' );
for ( auto part : parts )
{
std::string trimmedPart = RiaStdStringTools::trimString( part );
auto trimmedPart = RiaStdStringTools::trimString( part );
if ( !trimmedPart.empty() )
{

View File

@ -61,7 +61,8 @@ public:
{
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 )
return State::Acceptable;
else

View File

@ -257,3 +257,75 @@ TEST( RiaStdStringToolsTest, TestInvalidRangeStrings )
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 );
}
}