2017-11-03 02:54:54 -05:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Copyright (C) 2017 Statoil ASA
|
2019-09-06 03:40:57 -05:00
|
|
|
//
|
2017-11-03 02:54:54 -05:00
|
|
|
// ResInsight is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
2019-09-06 03:40:57 -05:00
|
|
|
//
|
2017-11-03 02:54:54 -05:00
|
|
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
2019-09-06 03:40:57 -05:00
|
|
|
//
|
|
|
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
2017-11-03 02:54:54 -05:00
|
|
|
// for more details.
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include "RiaStdStringTools.h"
|
|
|
|
|
2021-10-15 09:55:58 -05:00
|
|
|
#include "fast_float/include/fast_float/fast_float.h"
|
|
|
|
|
2021-09-13 11:20:44 -05:00
|
|
|
#include <cctype>
|
2021-10-15 10:28:08 -05:00
|
|
|
#include <charconv>
|
2021-09-13 11:20:44 -05:00
|
|
|
|
2022-03-25 08:16:25 -05:00
|
|
|
const std::string WHITESPACE = " \n\r\t\f\v";
|
|
|
|
|
2017-11-03 02:54:54 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
///
|
2017-11-03 02:54:54 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2022-03-25 08:16:25 -05:00
|
|
|
std::string RiaStdStringTools::leftTrimString( const std::string& s )
|
|
|
|
{
|
|
|
|
size_t start = s.find_first_not_of( WHITESPACE );
|
|
|
|
return ( start == std::string::npos ) ? "" : s.substr( start );
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
std::string RiaStdStringTools::rightTrimString( const std::string& s )
|
2017-11-03 02:54:54 -05:00
|
|
|
{
|
2022-03-25 08:16:25 -05:00
|
|
|
size_t end = s.find_last_not_of( WHITESPACE );
|
|
|
|
return ( end == std::string::npos ) ? "" : s.substr( 0, end + 1 );
|
|
|
|
}
|
2017-11-03 02:54:54 -05:00
|
|
|
|
2022-03-25 08:16:25 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
std::string RiaStdStringTools::trimString( const std::string& s )
|
|
|
|
{
|
|
|
|
return rightTrimString( leftTrimString( s ) );
|
2017-11-03 02:54:54 -05:00
|
|
|
}
|
2017-11-03 08:36:59 -05:00
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
///
|
2017-11-03 08:36:59 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
bool RiaStdStringTools::isNumber( const std::string& s, char decimalPoint )
|
2017-11-03 08:36:59 -05:00
|
|
|
{
|
2019-10-25 09:38:08 -05:00
|
|
|
if ( s.empty() ) return false;
|
2019-09-06 03:40:57 -05:00
|
|
|
if ( findCharMatchCount( s, decimalPoint ) > 1 ) return false;
|
|
|
|
if ( findCharMatchCount( s, '-' ) > 1 ) return false;
|
|
|
|
if ( findCharMatchCount( s, 'e' ) > 1 ) return false;
|
|
|
|
if ( findCharMatchCount( s, 'E' ) > 1 ) return false;
|
|
|
|
|
2019-10-25 09:38:08 -05:00
|
|
|
std::string matchChars( "0123456789eE-+" );
|
2019-09-06 03:40:57 -05:00
|
|
|
matchChars.append( 1, decimalPoint );
|
2019-10-25 09:38:08 -05:00
|
|
|
|
|
|
|
auto it = s.find_first_not_of( matchChars );
|
|
|
|
|
|
|
|
return ( it == std::string::npos );
|
2017-11-03 08:36:59 -05:00
|
|
|
}
|
|
|
|
|
2018-09-13 05:38:17 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
///
|
2018-09-13 05:38:17 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
int16_t RiaStdStringTools::toInt16( const std::string& s )
|
2018-09-13 05:38:17 -05:00
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
return (int16_t)toInt( s );
|
2018-09-13 05:38:17 -05:00
|
|
|
}
|
|
|
|
|
2017-11-03 08:36:59 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
///
|
2017-11-03 08:36:59 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
int RiaStdStringTools::toInt( const std::string& s )
|
2017-11-03 08:36:59 -05:00
|
|
|
{
|
|
|
|
int intValue = -1;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
intValue = std::stoi( s );
|
2017-11-03 08:36:59 -05:00
|
|
|
}
|
2019-09-06 03:40:57 -05:00
|
|
|
catch ( ... )
|
2017-11-03 08:36:59 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
return intValue;
|
|
|
|
}
|
2017-11-03 09:26:56 -05:00
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
///
|
2017-11-03 09:26:56 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
double RiaStdStringTools::toDouble( const std::string& s )
|
2017-11-03 09:26:56 -05:00
|
|
|
{
|
|
|
|
double doubleValue = -1.0;
|
|
|
|
|
|
|
|
char* end;
|
2019-09-06 03:40:57 -05:00
|
|
|
doubleValue = std::strtod( s.data(), &end );
|
2017-11-03 09:26:56 -05:00
|
|
|
|
|
|
|
return doubleValue;
|
|
|
|
}
|
2017-11-06 14:18:34 -06:00
|
|
|
|
2018-05-03 02:53:25 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
///
|
2018-05-03 02:53:25 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
bool RiaStdStringTools::containsAlphabetic( const std::string& s )
|
2018-05-03 02:53:25 -05:00
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
return std::find_if( s.begin(), s.end(), []( char c ) { return isalpha( c ); } ) != s.end();
|
2018-05-03 02:53:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
///
|
2018-05-03 02:53:25 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
bool RiaStdStringTools::startsWithAlphabetic( const std::string& s )
|
2018-05-03 02:53:25 -05:00
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
if ( s.empty() ) return false;
|
2018-05-03 02:53:25 -05:00
|
|
|
|
2019-09-06 03:40:57 -05:00
|
|
|
return isalpha( s[0] ) != 0;
|
2018-05-03 02:53:25 -05:00
|
|
|
}
|
|
|
|
|
2021-09-13 04:37:55 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-10-15 09:55:58 -05:00
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
bool RiaStdStringTools::toDouble( const std::string_view& s, double& value )
|
|
|
|
{
|
|
|
|
auto resultObject = fast_float::from_chars( s.data(), s.data() + s.size(), value );
|
|
|
|
|
|
|
|
return ( resultObject.ec == std::errc() );
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-10-15 10:28:08 -05:00
|
|
|
bool RiaStdStringTools::toInt( const std::string_view& s, int& value )
|
2021-10-15 09:55:58 -05:00
|
|
|
{
|
2021-10-15 10:28:08 -05:00
|
|
|
auto resultObject = std::from_chars( s.data(), s.data() + s.size(), value );
|
2021-10-15 09:55:58 -05:00
|
|
|
|
2021-10-15 10:28:08 -05:00
|
|
|
return ( resultObject.ec == std::errc() );
|
2021-10-15 09:55:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-09-13 04:37:55 -05:00
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
std::string RiaStdStringTools::toUpper( const std::string& s )
|
|
|
|
{
|
|
|
|
auto strCopy( s );
|
|
|
|
std::transform( strCopy.begin(), strCopy.end(), strCopy.begin(), []( unsigned char c ) { return std::toupper( c ); } );
|
|
|
|
|
|
|
|
return strCopy;
|
|
|
|
}
|
|
|
|
|
2018-12-14 02:20:28 -06:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
///
|
2018-12-14 02:20:28 -06:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
bool RiaStdStringTools::endsWith( const std::string& mainStr, const std::string& toMatch )
|
2018-12-14 02:20:28 -06:00
|
|
|
{
|
2019-09-06 03:40:57 -05:00
|
|
|
if ( mainStr.size() >= toMatch.size() &&
|
|
|
|
mainStr.compare( mainStr.size() - toMatch.size(), toMatch.size(), toMatch ) == 0 )
|
2018-12-14 02:20:28 -06:00
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-11-06 14:18:34 -06:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
///
|
2017-11-06 14:18:34 -06:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2021-09-13 04:37:55 -05:00
|
|
|
std::vector<std::string> RiaStdStringTools::splitString( const std::string& s, char delimiter )
|
2017-11-06 14:18:34 -06:00
|
|
|
{
|
|
|
|
std::vector<std::string> words;
|
|
|
|
|
2021-09-13 04:37:55 -05:00
|
|
|
splitByDelimiter( s, words, delimiter );
|
2017-11-06 14:18:34 -06:00
|
|
|
|
|
|
|
return words;
|
|
|
|
}
|
2017-11-22 13:34:18 -06:00
|
|
|
|
2021-09-13 04:37:55 -05:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
///
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
std::string RiaStdStringTools::joinStrings( const std::vector<std::string>& s, char delimiter )
|
|
|
|
{
|
2023-01-19 01:20:07 -06:00
|
|
|
std::string joinedString;
|
2021-09-13 04:37:55 -05:00
|
|
|
|
2023-01-19 01:20:07 -06:00
|
|
|
for ( const auto& str : s )
|
|
|
|
{
|
|
|
|
if ( !joinedString.empty() )
|
|
|
|
{
|
|
|
|
joinedString += delimiter;
|
|
|
|
}
|
|
|
|
|
|
|
|
joinedString += str;
|
|
|
|
}
|
|
|
|
|
|
|
|
return joinedString;
|
2021-09-13 04:37:55 -05:00
|
|
|
}
|
|
|
|
|
2017-11-22 13:34:18 -06:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
///
|
2017-11-22 13:34:18 -06:00
|
|
|
//--------------------------------------------------------------------------------------------------
|
2019-09-06 03:40:57 -05:00
|
|
|
size_t RiaStdStringTools::findCharMatchCount( const std::string& s, char c )
|
2017-11-22 13:34:18 -06:00
|
|
|
{
|
|
|
|
size_t count = 0;
|
2019-09-06 03:40:57 -05:00
|
|
|
size_t pos = 0;
|
|
|
|
while ( ( pos = s.find_first_of( c, pos + 1 ) ) != std::string::npos )
|
2017-11-22 13:34:18 -06:00
|
|
|
{
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
2020-05-24 04:36:28 -05:00
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
/// Function to find Levenshtein Distance between two strings (x and y).
|
|
|
|
/// Adapted from pseudocode from wikipedia: https://en.wikipedia.org/wiki/Levenshtein_distance
|
|
|
|
/// Implementation is the Wagner-Fischer variant: https://en.wikipedia.org/wiki/Wagner-Fischer_algorithm
|
|
|
|
///
|
|
|
|
/// Return value is higher when strings are more "different", and zero when strings are equal.
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
int RiaStdStringTools::computeEditDistance( const std::string& x, const std::string& y )
|
|
|
|
{
|
|
|
|
// for all i and j, T[i,j] will hold the Levenshtein distance between
|
|
|
|
// the first i characters of x and the first j characters of y
|
2020-05-24 11:42:59 -05:00
|
|
|
int m = static_cast<int>( x.length() );
|
|
|
|
int n = static_cast<int>( y.length() );
|
2020-05-24 04:36:28 -05:00
|
|
|
|
|
|
|
std::vector<std::vector<int>> T( m + 1, std::vector<int>( n + 1, 0 ) );
|
|
|
|
|
|
|
|
// source prefixes can be transformed into empty string by
|
|
|
|
// dropping all characters
|
|
|
|
for ( int i = 1; i <= m; i++ )
|
|
|
|
T[i][0] = i;
|
|
|
|
|
|
|
|
// target prefixes can be reached from empty source prefix
|
|
|
|
// by inserting every character
|
|
|
|
for ( int j = 1; j <= n; j++ )
|
|
|
|
T[0][j] = j;
|
|
|
|
|
|
|
|
// fill the lookup table in bottom-up manner
|
|
|
|
for ( int i = 1; i <= m; i++ )
|
|
|
|
{
|
|
|
|
for ( int j = 1; j <= n; j++ )
|
|
|
|
{
|
|
|
|
int substitutionCost;
|
|
|
|
if ( x[i - 1] == y[j - 1] )
|
|
|
|
substitutionCost = 0;
|
|
|
|
else
|
|
|
|
substitutionCost = 1;
|
|
|
|
|
|
|
|
int deletion = T[i - 1][j] + 1;
|
|
|
|
int insertion = T[i][j - 1] + 1;
|
|
|
|
int replacement = T[i - 1][j - 1] + substitutionCost;
|
|
|
|
T[i][j] = std::min( std::min( deletion, insertion ), replacement );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The distance between the two full strings as the last value computed.
|
|
|
|
return T[m][n];
|
|
|
|
}
|