Starting from 2021-07-01, all LRZ GitLab users will be required to explicitly accept the GitLab Terms of Service. Please see the detailed information at https://doku.lrz.de/display/PUBLIC/GitLab and make sure that your projects conform to the requirements.

Commit 299e2574 authored by schultezub's avatar schultezub
Browse files

* added WeaklyTypedPointerTraits

 * added TextFileParser
 * fixed StringUtils

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@167 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent c2bc7a7c
......@@ -6,102 +6,102 @@
namespace TUMVis {
std::string StringUtils::lowercase(const std::string& str) {
std::string toReturn(str);
std::transform(toReturn.begin(), toReturn.end(), toReturn.begin(), ::tolower);
return toReturn;
std::string toReturn(str);
std::transform(toReturn.begin(), toReturn.end(), toReturn.begin(), ::tolower);
return toReturn;
}
std::string StringUtils::uppercase(const std::string& str) {
std::string toReturn(str);
std::transform(toReturn.begin(), toReturn.end(), toReturn.begin(), ::toupper);
std::string toReturn(str);
std::transform(toReturn.begin(), toReturn.end(), toReturn.begin(), ::toupper);
return toReturn;
}
std::vector<std::string> StringUtils::parseFloats(const std::string& str) {
static const std::string floatCharacters("0123456789.-");
std::vector<std::string> toReturn;
size_t strpos = 0;
size_t endpos = 0;
// we just started or just finished parsing an entry, check if finished and skip to beginning of next entry
while ((endpos != std::string::npos) && (strpos = str.find_first_of(floatCharacters, strpos)) != std::string::npos) {
// strpos currently points to the beginning of a float, now find its end
endpos = str.find_first_not_of(floatCharacters, strpos+1);
// extract float
std::string token = str.substr(strpos, endpos - strpos);
// sanity checks
size_t signPos = token.rfind('-');
if (signPos == 0 || signPos == std::string::npos) { // sign only allowed at beginning
if (token.find('.') == token.rfind('.')) { // only one . allowed
toReturn.push_back(token);
}
}
strpos = endpos + 1;
}
return toReturn;
std::vector<std::string> StringUtils::parseFloats(const std::string& str) {
static const std::string floatCharacters("0123456789.-");
std::vector<std::string> toReturn;
size_t strpos = 0;
size_t endpos = 0;
// we just started or just finished parsing an entry, check if finished and skip to beginning of next entry
while ((endpos != std::string::npos) && (strpos = str.find_first_of(floatCharacters, strpos)) != std::string::npos) {
// strpos currently points to the beginning of a float, now find its end
endpos = str.find_first_not_of(floatCharacters, strpos+1);
// extract float
std::string token = str.substr(strpos, endpos - strpos);
// sanity checks
size_t signPos = token.rfind('-');
if (signPos == 0 || signPos == std::string::npos) { // sign only allowed at beginning
if (token.find('.') == token.rfind('.')) { // only one . allowed
toReturn.push_back(token);
}
}
strpos = endpos + 1;
}
return toReturn;
}
std::string StringUtils::replaceAll(const std::string& str, const std::string& from, const std::string& to) {
std::string toReturn(str);
std::string::size_type strpos = 0;
std::string::size_type foundpos;
while((foundpos = toReturn.find(from, strpos)) != std::string::npos) {
toReturn.replace(foundpos, from.size(), to);
strpos = foundpos + to.size();
}
std::string toReturn(str);
std::string::size_type strpos = 0;
std::string::size_type foundpos;
while((foundpos = toReturn.find(from, strpos)) != std::string::npos) {
toReturn.replace(foundpos, from.size(), to);
strpos = foundpos + to.size();
}
return toReturn;
}
std::vector<std::string> StringUtils::split(const std::string& line, const std::string& delimiter) {
std::vector<std::string> toReturn;
std::string::size_type linepos = 0;
std::string::size_type endpos = 0;
// we are at the beginning of an entry, skip whitespaces and check if not already reached end of line
while (endpos != std::string::npos) {
endpos = line.find_first_of(delimiter, linepos);
toReturn.push_back(line.substr(linepos, endpos - linepos));
linepos = endpos + 1;
}
std::vector<std::string> toReturn;
std::string::size_type linepos = 0;
std::string::size_type endpos = 0;
// we are at the beginning of an entry, skip whitespaces and check if not already reached end of line
while (endpos != std::string::npos) {
endpos = line.find_first_of(delimiter, linepos);
toReturn.push_back(line.substr(linepos, endpos - linepos));
linepos = endpos + 1;
}
return toReturn;
}
std::vector<std::string> StringUtils::spiltStringsafe(const std::string& str, const std::string& delimiter, char quotes /*= '"'*/, const std::string& whitespace /*= " \t"*/) {
std::vector<std::string> toReturn;
std::string::size_type strpos = 0;
std::string::size_type endpos = 0;
// we are at the beginning of an entry, skip whitespaces and check if not already reached end of str
while ((endpos != std::string::npos) && (strpos = str.find_first_not_of(whitespace, strpos)) != std::string::npos) {
// now strpos points to the first non blank character, here starts the entry
// check whether there are quotes
if (str[strpos] == quotes) {
// find position of closing quotes
endpos = str.find_first_of('"', strpos + 1);
std::string toPush = str.substr(strpos + 1 , endpos - strpos - 1);
// ensure we haven't found double quotes ("") which shall be resolved to one double quote in resulting string
while ((endpos != std::string::npos) && (endpos + 1 < str.length()) && (str[endpos + 1] == '"')) {
strpos = endpos + 1;
endpos = str.find_first_of('"', endpos + 2);
toPush.append(str.substr(strpos, endpos - strpos));
}
// push string in quotes onto toReturn
toReturn.push_back(StringUtils::trim(toPush, whitespace));
// ignore everything until next delimiter
endpos = str.find_first_of(delimiter, endpos);
}
// ok, this entry is not in quotes - just push everything until next delimiter onto toReturn
else {
endpos = str.find_first_of(delimiter, strpos);
toReturn.push_back(StringUtils::trim(str.substr(strpos, endpos - strpos), whitespace));
}
strpos = endpos + 1;
}
std::vector<std::string> StringUtils::splitStringsafe(const std::string& str, const std::string& delimiter, char quotes /*= '"'*/, const std::string& whitespace /*= " \t"*/) {
std::vector<std::string> toReturn;
std::string::size_type strpos = 0;
std::string::size_type endpos = 0;
// we are at the beginning of an entry, skip whitespaces and check if not already reached end of str
while ((endpos != std::string::npos) && (strpos = str.find_first_not_of(whitespace, strpos)) != std::string::npos) {
// now strpos points to the first non blank character, here starts the entry
// check whether there are quotes
if (str[strpos] == quotes) {
// find position of closing quotes
endpos = str.find_first_of('"', strpos + 1);
std::string toPush = str.substr(strpos + 1 , endpos - strpos - 1);
// ensure we haven't found double quotes ("") which shall be resolved to one double quote in resulting string
while ((endpos != std::string::npos) && (endpos + 1 < str.length()) && (str[endpos + 1] == '"')) {
strpos = endpos + 1;
endpos = str.find_first_of('"', endpos + 2);
toPush.append(str.substr(strpos, endpos - strpos));
}
// push string in quotes onto toReturn
toReturn.push_back(StringUtils::trim(toPush, whitespace));
// ignore everything until next delimiter
endpos = str.find_first_of(delimiter, endpos);
}
// ok, this entry is not in quotes - just push everything until next delimiter onto toReturn
else {
endpos = str.find_first_of(delimiter, strpos);
toReturn.push_back(StringUtils::trim(str.substr(strpos, endpos - strpos), whitespace));
}
strpos = endpos + 1;
}
return toReturn;
}
......
#ifndef STRINGUTILS_H__
#define STRINGUTILS_H__
#include "tgt/logmanager.h"
#include <exception>
#include <sstream>
#include <string>
#include <vector>
......@@ -16,60 +16,61 @@ namespace TUMVis {
* \todo Test, test, test!
*/
class StringUtils {
public:
/**
* Converts the string \a str to lowercase.
* \param str String to convert.
* \return Lowercase version of \a str.
*/
static std::string lowercase(const std::string& str);
static std::string lowercase(const std::string& str);
/**
* Converts the string \a str to uppercase.
* \param str String to convert.
* \return Uppercase version of \a str.
*/
static std::string uppercase(const std::string& str);
/**
* Splits \a str into a vector of strings representing float values.
* Floats formatted as [-][0-9]*.[0-9]* are considered, all other characters in between are ignored.
*
* \param str Input string to parse.
*
* \note TODO: The detection algorithm is a litte simplified and will not yield correct results
* in every case.
**/
static std::vector<std::string> parseFloats(const std::string& str);
/**
* Replaces all occurences of \a from in \a str with \a to.
* \param str String to perform replacement on.
* \param from String to be replaced.
* \param to String repace.
* \return \a str with all occurences of \a from replaced with \a to.
*/
static std::string replaceAll(const std::string& str, const std::string& from, const std::string& to);
/**
* Splits the string \a str into pieces separated by the delimiters in \a delimiter.
* \param str String to split.
* \param delimiter Set of delimiters.
* \return Vector of the split substrings.
*/
static std::vector<std::string> split(const std::string& str, const std::string& delimiter);
static std::string uppercase(const std::string& str);
/**
* Splits \a str into a vector of strings representing float values.
* Floats formatted as [-][0-9]*.[0-9]* are considered, all other characters in between are ignored.
*
* \param str Input string to parse.
*
* \note TODO: The detection algorithm is a litte simplified and will not yield correct results
* in every case.
**/
static std::vector<std::string> parseFloats(const std::string& str);
/**
* Replaces all occurences of \a from in \a str with \a to.
* \param str String to perform replacement on.
* \param from String to be replaced.
* \param to String repace.
* \return \a str with all occurences of \a from replaced with \a to.
*/
static std::string replaceAll(const std::string& str, const std::string& from, const std::string& to);
/**
* Splits the string \a str into trimmed pieces separated by the delimiters in \a delimiter.
* Delimiters in quoted strings (\a quotes) will be ignored, double quotes within quoted strings will be
* interpreted as literal quotes. Each token will be trimmed.
*
* \param str String to split.
* \param delimiter Set of delimiters.
* Splits the string \a str into pieces separated by the delimiters in \a delimiter.
* \param str String to split.
* \param delimiter Set of delimiters.
* \return Vector of the split substrings.
*/
static std::vector<std::string> split(const std::string& str, const std::string& delimiter);
/**
* Splits the string \a str into trimmed pieces separated by the delimiters in \a delimiter.
* Delimiters in quoted strings (\a quotes) will be ignored, double quotes within quoted strings will be
* interpreted as literal quotes. Each token will be trimmed.
*
* \param str String to split.
* \param delimiter Set of delimiters.
* \param quotes Character used for quotes.
* \param whitespace Set of whitespace characters which shall be removed during trimming.
* \return Vector of the split substrings.
*/
static std::vector<std::string> spiltStringsafe(const std::string& str, const std::string& delimiter, char quotes = '"', const std::string& whitespace = " \t");
static std::vector<std::string> splitStringsafe(const std::string& str, const std::string& delimiter, char quotes = '"', const std::string& whitespace = " \t");
/**
* Trims the string \a str.
......@@ -81,60 +82,61 @@ namespace TUMVis {
*/
static std::string trim(const std::string& str, const std::string& whitespace = " \t");
/**
* Converts the value \a value to a string.
* \param value The value to convert, must be compatible with std::stringstream.
* \return A string representation of \a value.
*/
template<class T>
std::string toString(const T& value);
/**
* Converts the string \a str to its original value.
* \param str The string to convert
* \return The back-converted value of \a str, type must be compatible with std::stringstream.
*/
template<class T>
T fromString(const std::string& str);
/**
* Joins the substrings in \a tokens together using \a delimiter in between.
* \param tokens List of substrings to join.
* \param delimiter Delimiter which shall be placed between the substrings.
* \return A string containing the joined substrings.
*/
template<typename T>
/**
* Converts the value \a value to a string.
* \param value The value to convert, must be compatible with std::stringstream.
* \return A string representation of \a value.
*/
template<class T>
static std::string toString(const T& value);
/**
* Converts the string \a str to its original value.
* \param str The string to convert
* \return The back-converted value of \a str, type must be compatible with std::stringstream.
* \throw std::exception on conversion failure
*/
template<class T>
static T fromString(const std::string& str) throw (std::exception);
/**
* Joins the substrings in \a tokens together using \a delimiter in between.
* \param tokens List of substrings to join.
* \param delimiter Delimiter which shall be placed between the substrings.
* \return A string containing the joined substrings.
*/
template<typename T>
static std::string join(const std::vector<T>& tokens, const std::string& delimiter);
};
// - Template definition --------------------------------------------------------------------------
template<class T>
std::string toString(const T& value) {
std::ostringstream stream;
stream << value;
return stream.str();
}
template<class T>
T fromString(const std::string& str) {
T toReturn;
std::istringstream stream;
stream.str(str);
if (!(stream >> toReturn))
LERRORC("TumVis.core.tools.StringUtils::fromString()", "failed to convert string '" + str + "'");
return toReturn;
}
template<typename T>
std::string join(const std::vector<T>& tokens, const std::string& delimiter) {
if (tokens.empty())
return "";
std::stringstream s;
s << tokens[0];
for (std::vector<T>::size_type i = 1; i < tokens.size(); ++i)
s << delimiter << tokens[i];
return s.str();
template<class T>
std::string toString(const T& value) {
std::ostringstream stream;
stream << value;
return stream.str();
}
template<class T>
T fromString(const std::string& str) throw (std::exception) {
T toReturn;
std::istringstream stream;
stream.str(str);
if (!(stream >> toReturn))
throw std::exception("Failed to convert string '" + str + "'");
return toReturn;
}
template<typename T>
std::string join(const std::vector<T>& tokens, const std::string& delimiter) {
if (tokens.empty())
return "";
std::stringstream s;
s << tokens[0];
for (std::vector<T>::size_type i = 1; i < tokens.size(); ++i)
s << delimiter << tokens[i];
return s.str();
}
}
......
#include "textfileparser.h"
#include <sstream>
namespace TUMVis {
TextFileParser::TextFileParser(const std::string& url, bool caseSensitiveKeys, const std::string& delimiters, const std::string& whitespace /*= " \t"*/)
: _url(url)
, _caseSensitiveKeys(caseSensitiveKeys)
, _delimiters(delimiters)
, _whitespace(whitespace)
{
}
bool TextFileParser::hasToken(const std::string& key) const {
return (_tokens.find(key) != _tokens.end());
}
const std::string& TextFileParser::getString(const std::string& key) const throw (tgt::CorruptedFileException) {
std::map<std::string, std::string>::const_iterator it = (_caseSensitiveKeys ? _tokens.find(key) : _tokens.find(StringUtils::lowercase(key)));
if (it == _tokens.end()) {
throw tgt::CorruptedFileException("No token with key " + key + " found.", _url);
}
else {
return it->second;
}
}
bool TextFileParser::getBool(const std::string& key) const throw (tgt::CorruptedFileException) {
std::string lc = StringUtils::lowercase(getString(key));
if ((lc == "0") || (lc == "false"))
return false;
else if ((lc == "1") || (lc == "true"))
return true;
else
throw tgt::CorruptedFileException("Error parsing key " + key + " to bool.", _url);
}
int TextFileParser::getInt(const std::string& key) const throw (tgt::CorruptedFileException) {
std::string str = getString(key);
try {
return StringUtils::fromString<int>(str);
}
catch (std::exception& e) {
throw tgt::CorruptedFileException("Error parsing key " + key + " to int: " + e.what(), _url);
}
}
tgt::ivec2 TextFileParser::getIvec2(const std::string& key) const throw (tgt::CorruptedFileException){
std::string str = getString(key);
try {
return StringUtils::fromString<tgt::ivec2>(str);
}
catch (std::exception& e) {
throw tgt::CorruptedFileException("Error parsing key " + key + " to ivec2: " + e.what(), _url);
}
}
tgt::ivec3 TextFileParser::getIvec3(const std::string& key) const throw (tgt::CorruptedFileException){
std::string str = getString(key);
try {
return StringUtils::fromString<tgt::ivec3>(str);
}
catch (std::exception& e) {
throw tgt::CorruptedFileException("Error parsing key " + key + " to ivec3: " + e.what(), _url);
}
}
tgt::ivec4 TextFileParser::getIvec4(const std::string& key) const throw (tgt::CorruptedFileException){
std::string str = getString(key);
try {
return StringUtils::fromString<tgt::ivec4>(str);
}
catch (std::exception& e) {
throw tgt::CorruptedFileException("Error parsing key " + key + " to ivec4: " + e.what(), _url);
}
}
float TextFileParser::getFloat(const std::string& key) const throw (tgt::CorruptedFileException) {
std::string str = getString(key);
try {
return StringUtils::fromString<float>(str);
}
catch (std::exception& e) {
throw tgt::CorruptedFileException("Error parsing key " + key + " to float: " + e.what(), _url);
}
}
tgt::vec2 TextFileParser::getVec2(const std::string& key) const throw (tgt::CorruptedFileException) {
std::string str = getString(key);
try {
return StringUtils::fromString<tgt::vec2>(str);
}
catch (std::exception& e) {
throw tgt::CorruptedFileException("Error parsing key " + key + " to vec2: " + e.what(), _url);
}
}
tgt::vec3 TextFileParser::getVec3(const std::string& key) const throw (tgt::CorruptedFileException) {
std::string str = getString(key);
try {
return StringUtils::fromString<tgt::vec3>(str);
}
catch (std::exception& e) {
throw tgt::CorruptedFileException("Error parsing key " + key + " to vec3: " + e.what(), _url);
}
}
tgt::vec4 TextFileParser::getVec4(const std::string& key) const throw (tgt::CorruptedFileException) {
std::string str = getString(key);
try {
return StringUtils::fromString<tgt::vec4>(str);
}
catch (std::exception& e) {
throw tgt::CorruptedFileException("Error parsing key " + key + " to vec4: " + e.what(), _url);
}
}
}
\ No newline at end of file
#ifndef TEXTFILEPARSER_H__
#define TEXTFILEPARSER_H__
#include "tgt/exception.h"
#include "tgt/filesystem.h"
#include "tgt/vector.h"
#include "core/tools/stringutils.h"
#include <map>
#include <functional>
#include <string>
#include <vector>
namespace TUMVis {
/**
* Helper class for parsing simple text files containing key-value pairs.
* The file will be read in text mode and split into single key-value items using the template argument
* functor of parse(). Finally, each item will be split into key and value using the given delimiters.
*
* \todo Better vector support (e.g. "x,y,z" format)
* Test and debug o_O
*/
class TextFileParser {
public:
/**
* Item separator for letting each line in the file result in one key-value pair item.
* \note The behaviour is not implemented as functor but by template specialization!
*/
struct ItemSeparatorLines {
// no operator() to implement due to template specialization
};
/**
* Creates a new text file parser with the given settings.
* \param url URL of file
* \param caseSensitiveKeys Flag whether keys are case-sensitive or not
* \param delimiters Set of delimiters for separating key-value pair
* \param whitespace Set of characters identifying whitespace
*/
TextFileParser(const std::string& url, bool caseSensitiveKeys, const std::string& delimiters, const std::string& whitespace = " \t");
/**
* Performs the parsing of the text file into key-value pairs.
* The file will be read in text mode and split into single items using the template argument
* functor \ta T. Then, each item will be split into key-value pairs.
*
* \sa TextFileParser::ItemSeparatorLines
* \tparam T Functor for splitting the file into items, must implement std::unary_function<std::string, std::vector<std::string> >
* \throw tgt::FileException if file not found/not readable, tgt::CorruptedFileException on parsing errors during key-value pair parsing.
*/
template<class T>
void parse() throw (tgt::FileException, tgt::CorruptedFileException);
/**
* Checks whether there exists a token with the given key \a key.
* \param key The key to search for.
* \return True if a key-value pair with the given key is existent, otherwise false.
*/
bool hasToken(const std::string& key) const;
/**
* Returns the value to the given key \a key.