string_utils.cc

00001 /*
00002  *  This file is part of libcxxsupport.
00003  *
00004  *  libcxxsupport is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  libcxxsupport is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with libcxxsupport; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00017  */
00018 
00019 /*
00020  *  libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik
00021  *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
00022  *  (DLR).
00023  */
00024 
00025 /*
00026  *  This file contains the implementation of various convenience functions
00027  *  used by the Planck LevelS package.
00028  *
00029  *  Copyright (C) 2002-2014 Max-Planck-Society
00030  *  Author: Martin Reinecke
00031  */
00032 
00033 #include <sstream>
00034 #include <fstream>
00035 #include <iostream>
00036 #include <iomanip>
00037 #include <string>
00038 #include <cstring>
00039 #include <cctype>
00040 #include "string_utils.h"
00041 
00042 using namespace std;
00043 
00044 string trim (const string &orig)
00045   {
00046   string::size_type p1=orig.find_first_not_of(" \t");
00047   if (p1==string::npos) return "";
00048   string::size_type p2=orig.find_last_not_of(" \t");
00049   return orig.substr(p1,p2-p1+1);
00050   }
00051 
00052 template<typename T> string dataToString (const T &x)
00053   {
00054   ostringstream strstrm;
00055   strstrm << x;
00056   return trim(strstrm.str());
00057   }
00058 
00059 template<> string dataToString (const bool &x)
00060   { return x ? "T" : "F"; }
00061 template<> string dataToString (const string &x)
00062   { return trim(x); }
00063 template<> string dataToString (const float &x)
00064   {
00065   ostringstream strstrm;
00066   strstrm << setprecision(8) << x;
00067   return trim(strstrm.str());
00068   }
00069 template<> string dataToString (const double &x)
00070   {
00071   ostringstream strstrm;
00072   strstrm << setprecision(16) << x;
00073   return trim(strstrm.str());
00074   }
00075 template<> string dataToString (const long double &x)
00076   {
00077   ostringstream strstrm;
00078   strstrm << setprecision(25) << x;
00079   return trim(strstrm.str());
00080   }
00081 
00082 template string dataToString (const signed char &x);
00083 template string dataToString (const unsigned char &x);
00084 template string dataToString (const short &x);
00085 template string dataToString (const unsigned short &x);
00086 template string dataToString (const int &x);
00087 template string dataToString (const unsigned int &x);
00088 template string dataToString (const long &x);
00089 template string dataToString (const unsigned long &x);
00090 template string dataToString (const long long &x);
00091 template string dataToString (const unsigned long long &x);
00092 
00093 string intToString(int64 x, tsize width)
00094   {
00095   ostringstream strstrm;
00096   (x>=0) ? strstrm << setw(width) << setfill('0') << x
00097          : strstrm << "-" << setw(width-1) << setfill('0') << -x;
00098   string res = strstrm.str();
00099   planck_assert(res.size()==width,"number too large");
00100   return trim(res);
00101   }
00102 
00103 namespace {
00104 
00105 void end_stringToData (const string &x, const char *tn, istringstream &strstrm)
00106   {
00107   string error = string("conversion error in stringToData<")+tn+">(\""+x+"\")";
00108   planck_assert (strstrm,error);
00109   string rest;
00110   strstrm >> rest;
00111 //  rest=trim(rest);
00112   planck_assert (rest.length()==0,error);
00113   }
00114 
00115 } // unnamed namespace
00116 
00117 template<typename T> void stringToData (const string &x, T &value)
00118   {
00119   istringstream strstrm(x);
00120   strstrm >> value;
00121   end_stringToData (x,type2typename<T>(),strstrm);
00122   }
00123 
00124 template<> void stringToData (const string &x, string &value)
00125   { value = trim(x); }
00126 
00127 template<> void stringToData (const string &x, bool &value)
00128   {
00129   const char *fval[] = {"f","n","false",".false."};
00130   const char *tval[] = {"t","y","true",".true."};
00131   for (tsize i=0; i< sizeof(fval)/sizeof(fval[0]); ++i)
00132     if (equal_nocase(x,fval[i])) { value=false; return; }
00133   for (tsize i=0; i< sizeof(tval)/sizeof(tval[0]); ++i)
00134     if (equal_nocase(x,tval[i])) { value=true; return; }
00135   planck_fail("conversion error in stringToData<bool>(\""+x+"\")");
00136   }
00137 
00138 template void stringToData (const string &x, signed char &value);
00139 template void stringToData (const string &x, unsigned char &value);
00140 template void stringToData (const string &x, short &value);
00141 template void stringToData (const string &x, unsigned short &value);
00142 template void stringToData (const string &x, int &value);
00143 template void stringToData (const string &x, unsigned int &value);
00144 template void stringToData (const string &x, long &value);
00145 template void stringToData (const string &x, unsigned long &value);
00146 template void stringToData (const string &x, long long &value);
00147 template void stringToData (const string &x, unsigned long long &value);
00148 template void stringToData (const string &x, float &value);
00149 template void stringToData (const string &x, double &value);
00150 template void stringToData (const string &x, long double &value);
00151 
00152 bool equal_nocase (const string &a, const string &b)
00153   {
00154   if (a.size()!=b.size()) return false;
00155   for (tsize m=0; m<a.size(); ++m)
00156     if (tolower(a[m])!=tolower(b[m])) return false;
00157   return true;
00158   }
00159 
00160 string tolower(const string &input)
00161   {
00162   string result=input;
00163   for (tsize m=0; m<result.size(); ++m)
00164     result[m]=char(tolower(result[m]));
00165   return result;
00166   }
00167 
00168 void parse_file (const string &filename, map<string,string> &dict)
00169   {
00170   int lineno=0;
00171   dict.clear();
00172   ifstream inp(filename.c_str());
00173   planck_assert (inp,"Could not open parameter file '"+filename+"'.");
00174   while (inp)
00175     {
00176     string line;
00177     getline(inp, line);
00178     ++lineno;
00179     // remove potential carriage returns at the end of the line
00180     line=line.substr(0,line.find("\r"));
00181     line=line.substr(0,line.find("#"));
00182     line=trim(line);
00183     if (line.size()>0)
00184       {
00185       string::size_type eqpos=line.find("=");
00186       if (eqpos!=string::npos)
00187         {
00188         string key=trim(line.substr(0,eqpos)),
00189                value=trim(line.substr(eqpos+1,string::npos));
00190         if (key=="")
00191           cerr << "Warning: empty key in '" << filename << "', line "
00192                << lineno << endl;
00193         else
00194           {
00195           if (dict.find(key)!=dict.end())
00196             cerr << "Warning: key '" << key << "' multiply defined in '"
00197                  << filename << "', line " << lineno << endl;
00198           dict[key]=value;
00199           }
00200         }
00201       else
00202         cerr << "Warning: unrecognized format in '" << filename << "', line "
00203              << lineno << ":\n" << line << endl;
00204       }
00205     }
00206   }
00207 
00208 namespace {
00209 
00210 bool isParam (const string &s)
00211   {
00212   if (s.size()<2) return false;
00213   if (s[0]!='-') return false;
00214   return !(isdigit(s[1]) || (s[1]=='.'));
00215   }
00216 
00217 } // unnamed namespace
00218 
00219 void parse_cmdline_classic (int argc, const char **argv,
00220   const vector<string> &leading_args, map<string,string> &dict)
00221   {
00222   dict.clear();
00223   planck_assert(tsize(argc)>leading_args.size(),"not enough arguments");
00224   for (tsize i=0; i<leading_args.size(); ++i)
00225     dict[leading_args[i]] = argv[i+1];
00226   int curarg=leading_args.size()+1;
00227   while (curarg<argc)
00228     {
00229     string param=argv[curarg];
00230     planck_assert(isParam(param),"unrecognized command line format");
00231     if ((curarg==argc-1) || isParam(argv[curarg+1]))
00232       {
00233       dict[param.substr(1)]="true";
00234       ++curarg;
00235       }
00236     else
00237       {
00238       dict[param.substr(1)]=argv[curarg+1];
00239       curarg+=2;
00240       }
00241     }
00242   }
00243 
00244 void parse_cmdline_classic (int argc, const char **argv,
00245   map<string,string> &dict)
00246   { parse_cmdline_classic (argc, argv, vector<string>(), dict); }
00247 
00248 void parse_cmdline_equalsign (int argc, const char **argv,
00249   const vector<string> &leading_args, map<string,string> &dict)
00250   {
00251   dict.clear();
00252   planck_assert(tsize(argc)>leading_args.size(),"not enough arguments");
00253   for (tsize i=0; i<leading_args.size(); ++i)
00254     dict[leading_args[i]] = argv[i+1];
00255   for (int i=leading_args.size()+1; i<argc; ++i)
00256     {
00257     string arg=trim(argv[i]);
00258     if (arg.size()>0)
00259       {
00260       string::size_type eqpos=arg.find("=");
00261       if (eqpos!=string::npos)
00262         {
00263         string key=trim(arg.substr(0,eqpos)),
00264                value=trim(arg.substr(eqpos+1,string::npos));
00265         if (key=="")
00266           cerr << "Warning: empty key in argument'" << arg << "'" << endl;
00267         else
00268           {
00269           if (dict.find(key)!=dict.end())
00270             cerr << "Warning: key '" << key << "' multiply defined" << endl;
00271           dict[key]=value;
00272           }
00273         }
00274       else
00275         cerr << "Warning: unrecognized format in argument '" << arg << "'"
00276              << endl;
00277       }
00278     }
00279   }
00280 
00281 void parse_cmdline_equalsign (int argc, const char **argv,
00282   map<string,string> &dict)
00283   { parse_cmdline_equalsign (argc, argv, vector<string>(), dict); }
00284 
00285 namespace {
00286 
00287 template<typename T> void split (istream &stream, vector<T> &list)
00288   {
00289   list.clear();
00290   while (stream)
00291     {
00292     string word;
00293     stream >> word;
00294     planck_assert (stream||stream.eof(),
00295       string("error while splitting stream into ") + type2typename<T>()
00296       + "components");
00297     if (stream) list.push_back(stringToData<T>(word));
00298     }
00299   }
00300 
00301 } // unnamed namespace
00302 
00303 template<typename T> void split (const string &inp, vector<T> &list)
00304   {
00305   istringstream stream(inp);
00306   split (stream,list);
00307   }
00308 
00309 template void split (const string &inp, vector<string> &list);
00310 template void split (const string &inp, vector<float> &list);
00311 template void split (const string &inp, vector<double> &list);
00312 template void split (const string &inp, vector<int> &list);
00313 template void split (const string &inp, vector<long> &list);
00314 
00315 void tokenize (const string &inp, char delim, vector<string> &list)
00316   {
00317   istringstream stream(inp);
00318   string token;
00319   list.clear();
00320   while (getline(stream,token,delim))
00321     list.push_back(token);
00322   }
00323 
00324 void parse_words_from_file (const string &filename, vector<string> &words)
00325   {
00326   words.clear();
00327   ifstream inp(filename.c_str());
00328   planck_assert (inp,"Could not open file '"+filename+"'.");
00329   while (inp)
00330     {
00331     string word;
00332     inp>>word;
00333     word=trim(word);
00334     if (word!="") words.push_back(word);
00335     }
00336   }

Generated on Thu Oct 8 14:48:51 2015 for LevelS C++ support library