#include "MantidKernel/Strings.h" #include "MantidKernel/Exception.h" #include "MantidKernel/UnitLabel.h" #include <Poco/StringTokenizer.h> #include <Poco/Path.h> #include <boost/algorithm/string.hpp> #include <boost/lexical_cast.hpp> #include <boost/shared_ptr.hpp> #include <boost/make_shared.hpp> #include <cmath> #include <fstream> #include <iomanip> #include <iostream> #include <list> #include <sstream> #include <cstring> #include <vector> using std::size_t; namespace Mantid { namespace Kernel { namespace Strings { //------------------------------------------------------------------------------------------------ /** Loads the entire contents of a text file into a string * * @param filename :: full path to file * @return string contents of text file */ std::string loadFile(const std::string & filename) { std::string retVal; std::string str; std::ifstream in; in.open(filename.c_str()); getline(in,str); while ( in ) { retVal += str + "\n"; getline(in,str); } in.close(); return retVal; } //------------------------------------------------------------------------------------------------ /** Return a string with all matching occurence-strings * * @param input :: input string * @param find_what :: will search for all occurences of this string * @param replace_with :: ... and replace them with this. * @return the modified string. */ std::string replace(const std::string &input, const std::string &find_what, const std::string &replace_with) { std::string output = input; std::string::size_type pos=0; while((pos=output.find(find_what, pos))!=std::string::npos) { output.erase(pos, find_what.length()); output.insert(pos, replace_with); pos+=replace_with.length(); } return output; } /** * Return a string with all occurrences of the characters in the input replaced by the replace string * @param input :: The input string to perform the replacement on * @param charStr :: Each occurrence of ANY character in this string within the input string will be replaced by substitute * @param substitute :: A substitute string * @return A new string with the characters replaced */ MANTID_KERNEL_DLL std::string replaceAll(const std::string & input, const std::string & charStr, const std::string & substitute) { std::string replaced; replaced.reserve(input.size()); std::string::const_iterator iend = input.end(); for( std::string::const_iterator itr = input.begin(); itr != iend; ++itr ) { char inputChar = (*itr); if( charStr.find_first_of(inputChar) == std::string::npos ) // Input string char is not one of those to be replaced { replaced.push_back(inputChar); } else { replaced.append(substitute); } } return replaced; } //------------------------------------------------------------------------------------------------ /** * Function to convert a number into hex * output (and leave the stream un-changed) * @param OFS :: Output stream * @param n :: Integer to convert * \todo Change this to a stream operator */ void printHex(std::ostream& OFS,const int n) { std::ios_base::fmtflags PrevFlags=OFS.flags(); OFS<<"Ox"; OFS.width(8); OFS.fill('0'); hex(OFS); OFS << n; OFS.flags(PrevFlags); return; } //------------------------------------------------------------------------------------------------ /** * Removes the multiple spaces in the line * @param Line :: Line to process * @return String with single space components */ std::string stripMultSpc(const std::string& Line) { std::string Out; int spc(1); int lastReal(-1); for(unsigned int i=0;i<Line.length();i++) { if (Line[i]!=' ' && Line[i]!='\t' && Line[i]!='\r' && Line[i]!='\n') { lastReal=i; spc=0; Out+=Line[i]; } else if (!spc) { spc=1; Out+=' '; } } lastReal++; if (lastReal<static_cast<int>(Out.length())) Out.erase(lastReal); return Out; } //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ /** * Checks that as least cnt letters of * works is part of the string. It is currently * case sensitive. It removes the Word if found * @param Line :: Line to process * @param Word :: Word to use * @param cnt :: Length of Word for significants [default =4] * @retval 1 on success (and changed Line) * @retval 0 on failure */ int extractWord(std::string& Line,const std::string& Word,const int cnt) { if (Word.empty()) return 0; size_t minSize(cnt>static_cast<int>(Word.size()) ? Word.size() : cnt); std::string::size_type pos=Line.find(Word.substr(0,minSize)); if (pos==std::string::npos) return 0; // Pos == Start of find size_t LinePt=minSize+pos; for(;minSize<Word.size() && LinePt<Line.size() && Word[minSize]==Line[LinePt];LinePt++,minSize++) { } Line.erase(pos,LinePt-(pos-1)); return 1; } //------------------------------------------------------------------------------------------------ /** If a word ends with a number representing a positive integer, return * the value of that int. * * @param word :: string possibly ending in a number * @return the number, or -1 if it does not end in a number */ int endsWithInt(const std::string & word) { if (word.empty()) return -1; int out = -1; // Find the index of the first number in the string (if any) int firstNumber = int(word.size()); for (int i=int(word.size())-1; i>=0; i--) { char c = word[i]; if ((c > '9') || (c < '0')) break; firstNumber = i; } // Convert the string of decimals to an int if (firstNumber < int(word.size())) { std::string part = word.substr(firstNumber, word.size()-firstNumber); if (!convert(part, out)) return -1; } return out; } //------------------------------------------------------------------------------------------------ /** * Check to see if S is the same as the * first part of a phrase. (case insensitive) * @param S :: string to check * @param fullPhrase :: complete phrase * @return 1 on success */ int confirmStr(const std::string& S,const std::string& fullPhrase) { const size_t nS(S.length()); const size_t nC(fullPhrase.length()); if (nS>nC || nS==0) return 0; for(size_t i=0;i<nS;i++) if (S[i]!=fullPhrase[i]) return 0; return 1; } //------------------------------------------------------------------------------------------------ /** * Gets a line and determine if there is addition component to add * in the case of a very long line. * @param fh :: input stream to get line * @param Out :: string up to last 'tab' or ' ' * @param Excess :: string after 'tab or ' ' * @param spc :: number of char to try to read * @retval 1 :: more line to be found * @retval -1 :: Error with file * @retval 0 :: line finished. */ int getPartLine(std::istream& fh,std::string& Out,std::string& Excess,const int spc) { //std::string Line; if (fh.good()) { char* ss=new char[spc+1]; const int clen = static_cast<int>(spc-Out.length()); fh.getline(ss,clen,'\n'); ss[clen+1]=0; // incase line failed to read completely Out+=static_cast<std::string>(ss); delete [] ss; // remove trailing comments std::string::size_type pos = Out.find_first_of("#!"); if (pos!=std::string::npos) { Out.erase(pos); return 0; } if (fh.gcount()==clen-1) // cont line { pos=Out.find_last_of("\t "); if (pos!=std::string::npos) { Excess=Out.substr(pos,std::string::npos); Out.erase(pos); } else Excess.erase(0,std::string::npos); fh.clear(); return 1; } return 0; } return -1; } //------------------------------------------------------------------------------------------------ /** * Removes all spaces from a string * except those with in the form '\ ' * @param CLine :: Line to strip * @return String without space */ std::string removeSpace(const std::string& CLine) { std::string Out; char prev='x'; for(unsigned int i=0;i<CLine.length();i++) { if (!isspace(CLine[i]) || prev=='\\') { Out+=CLine[i]; prev=CLine[i]; } } return Out; } //------------------------------------------------------------------------------------------------ /** * Reads a line from the stream of max length spc. * Trailing comments are removed. (with # or ! character) * @param fh :: already open file handle * @param spc :: max number of characters to read * @return String read. */ std::string getLine(std::istream& fh,const int spc) { char* ss=new char[spc+1]; std::string Line; if (fh.good()) { fh.getline(ss,spc,'\n'); ss[spc]=0; // incase line failed to read completely Line=ss; // remove trailing comments std::string::size_type pos = Line.find_first_of("#!"); if (pos!=std::string::npos) Line.erase(pos); } delete [] ss; return Line; } /** * Peek at a line without extracting it from the stream */ std::string peekLine(std::istream & fh) { std::string str; std::streampos pos = fh.tellg(); getline(fh, str); fh.seekg(pos); return strip(str); } //------------------------------------------------------------------------------------------------ /** * Determines if a string is only spaces * @param A :: string to check * @return 1 on an empty string , 0 on failure */ int isEmpty(const std::string& A) { std::string::size_type pos= A.find_first_not_of(" \t"); return (pos!=std::string::npos) ? 0 : 1; } //------------------------------------------------------------------------------------------------ /** * removes the string after the comment type of * '$ ' or '!' or '# ' * @param A :: String to process */ void stripComment(std::string& A) { std::string::size_type posA=A.find("$ "); std::string::size_type posB=A.find("# "); std::string::size_type posC=A.find("!"); if (posA>posB) posA=posB; if (posA>posC) posA=posC; if (posA!=std::string::npos) A.erase(posA,std::string::npos); return; } //------------------------------------------------------------------------------------------------ /** * Returns the string from the first non-space to the * last non-space * @param A :: string to process * @return shortened string */ std::string fullBlock(const std::string& A) { return strip(A); } //------------------------------------------------------------------------------------------------ /** Returns the string from the first non-space to the * last non-space * @param A :: string to process * @return shortened string */ std::string strip(const std::string& A) { std::string result(A); boost::trim(result); return result; } /** * Return true if the line is to be skipped (starts with #). * @param line :: The line to be checked * @return True if the line should be skipped */ bool skipLine(const std::string & line) { // Empty or comment return ( line.empty() || boost::starts_with(line, "#") ); } //------------------------------------------------------------------------------------------------ /** * Write out the line in the limited form for MCNPX * ie initial line from 0->72 after that 8 to 72 * (split on a space or comma) * @param Line :: full MCNPX line * @param OX :: ostream to write to */ void writeMCNPX(const std::string& Line,std::ostream& OX) { const int MaxLine(72); std::string::size_type pos(0); std::string X=Line.substr(0,MaxLine); std::string::size_type posB=X.find_last_of(" ,"); int spc(0); while (posB!=std::string::npos && static_cast<int>(X.length())>=MaxLine-spc) { pos+=posB+1; if (!isspace(X[posB])) posB++; const std::string Out=X.substr(0,posB); if (!isEmpty(Out)) { if (spc) OX<<std::string(spc,' '); OX<<X.substr(0,posB)<<std::endl; } spc=8; X=Line.substr(pos,MaxLine-spc); posB=X.find_last_of(" ,"); } if (!isEmpty(X)) { if (spc) OX<<std::string(spc,' '); OX<<X<<std::endl; } return; } //------------------------------------------------------------------------------------------------ /** * Splits the sting into parts that are space delminated. * @param Ln :: line component to strip * @return vector of components */ std::vector<std::string> StrParts(std::string Ln) { std::vector<std::string> Out; std::string Part; while(section(Ln,Part)) Out.push_back(Part); return Out; } /** * Splits a string into key value pairs and returns them as a map. Whitespace between separators is ignored * @param input :: The string containing the key/values * @param keyValSep :: The separator that splits a key and value [default: "="] * @param listSep :: The separator that splits elements of the list [default: ","] * @returns A map of keys->values */ std::map<std::string,std::string> splitToKeyValues(const std::string & input, const std::string & keyValSep, const std::string & listSep) { std::map<std::string,std::string> keyValues; const int splitOptions = Poco::StringTokenizer::TOK_IGNORE_EMPTY + Poco::StringTokenizer::TOK_TRIM; Poco::StringTokenizer listSplitter(input, listSep); for(auto iter = listSplitter.begin(); iter != listSplitter.end(); ++iter) { Poco::StringTokenizer keyValSplitter(*iter, keyValSep, splitOptions); if(keyValSplitter.count() == 2) { keyValues[keyValSplitter[0]] = keyValSplitter[1]; } } return keyValues; } //------------------------------------------------------------------------------------------------ /** * Converts a vax number into a standard unix number * @param A :: float number as read from a VAX file * @return float A in IEEE little eindian format */ float getVAXnum(const float A) { union { //char a[4]; float f; int ival; } Bd; int sign,expt,fmask; float frac; double onum; Bd.f=A; sign = (Bd.ival & 0x8000) ? -1 : 1; expt = ((Bd.ival & 0x7f80) >> 7); //reveresed ? if (!expt) return 0.0; fmask = ((Bd.ival & 0x7f) << 16) | ((Bd.ival & 0xffff0000) >> 16); expt-=128; fmask |= 0x800000; frac = (float) fmask / 0x1000000; onum = frac * static_cast<float>(sign) * pow(2.0,expt); return (float) onum; } //------------------------------------------------------------------------------------------------ /** * Takes a character string and evaluates * the first [typename T] object. The string is then * erase upt to the end of number. * The diffierence between this and section is that * it allows trailing characters after the number. * @param out :: place for output * @param A :: string to process * @return 1 on success 0 on failure */ template<typename T> int sectPartNum(std::string& A,T& out) { if (A.empty()) return 0; std::istringstream cx; T retval; cx.str(A); cx.clear(); cx>>retval; const std::streamoff xpt = cx.tellg(); if (xpt < 0) return 0; A.erase(0,static_cast<unsigned int>(xpt)); out=retval; return 1; } //------------------------------------------------------------------------------------------------ /** * Takes a character string and evaluates * the first [typename T] object. The string is then filled with * spaces upto the end of the [typename T] object * @param out :: place for output * @param cA :: char array for input and output. * @return 1 on success 0 on failure */ template<typename T> int section(char* cA,T& out) { if (!cA) return 0; std::string sA(cA); const int item(section(sA,out)); if (item) { strcpy(cA,sA.c_str()); return 1; } return 0; } /** * takes a character string and evaluates * the first \<T\> object. The string is then filled with * spaces upto the end of the \<T\> object * @param out :: place for output * @param A :: string for input and output. * @return 1 on success 0 on failure */ template<typename T> int section(std::string& A,T& out) { if (A.empty()) return 0; std::istringstream cx; T retval; cx.str(A); cx.clear(); cx>>retval; if (cx.fail()) return 0; const std::streamoff xpt = cx.tellg(); const char xc = static_cast<char>(cx.get()); if (!cx.fail() && !isspace(xc)) return 0; A.erase(0, static_cast<unsigned int>(xpt)); out=retval; return 1; } /** * Takes a character string and evaluates * the first [T] object. The string is then filled with * spaces upto the end of the [T] object. * This version deals with MCNPX numbers. Those * are numbers that are crushed together like * - 5.4938e+04-3.32923e-6 * @param out :: place for output * @param A :: string for input and output. * @return 1 on success 0 on failure */ template<typename T> int sectionMCNPX(std::string& A,T& out) { if (A.empty()) return 0; std::istringstream cx; T retval; cx.str(A); cx.clear(); cx>>retval; if (!cx.fail()) { const std::streamoff xpt = cx.tellg(); if( xpt < 0 ) { return 0; } const char xc=static_cast<char>(cx.get()); if (!cx.fail() && !isspace(xc) && (xc!='-' || xpt<5)) { return 0; } A.erase(0, static_cast<unsigned int>(xpt)); out=retval; return 1; } return 0; } //------------------------------------------------------------------------------------------------ /** * Takes a character string and evaluates * the first [typename T] object. The string is then * erase upto the end of number. * The diffierence between this and convert is that * it allows trailing characters after the number. * @param out :: place for output * @param A :: string to process * @retval number of char read on success * @retval 0 on failure */ template<typename T> int convPartNum(const std::string& A,T& out) { if (A.empty()) return 0; std::istringstream cx; T retval; cx.str(A); cx.clear(); cx>>retval; // If we have reached the end of the stream, then we need to clear the error as // it will cause the tellg() call to return -1. Not pretty but works for now. cx.clear(); const std::streamoff xpt = cx.tellg(); if (xpt<0) return 0; out=retval; return static_cast<int>(xpt); } //------------------------------------------------------------------------------------------------ /** * Convert a string into a value * @param A :: string to pass * @param out :: value if found * @return 0 on failure 1 on success */ template<typename T> int convert(const std::string& A,T& out) { if (A.empty()) return 0; std::istringstream cx; T retval; cx.str(A); cx.clear(); cx>>retval; if (cx.fail()) return 0; const char clast = static_cast<char>(cx.get()); if (!cx.fail() && !isspace(clast)) return 0; out=retval; return 1; } //------------------------------------------------------------------------------------------------ /** * Convert a string into a value * @param A :: string to pass * @param out :: value if found * @return 0 on failure 1 on success */ template<typename T> int convert(const char* A,T& out) { // No string, no conversion if (!A) return 0; std::string Cx=A; return convert(Cx,out); } //------------------------------------------------------------------------------------------------ /** Convert a number or other value to a string * * @param value :: templated value (e.g. a double) to convert * @return a string */ template<typename T> std::string toString(const T &value) { std::ostringstream mess; mess << value; return mess.str(); } /** * This assumes that the vector is sorted. * * @param value :: templated value (only works for integer types) to convert. * @return A reduced string representation. */ template<typename T> std::string toString(const std::vector<T> &value) { std::ostringstream mess; auto it = value.begin(); auto last = value.end(); T start; T stop; for (; it != last; ++it) { start = *(it); stop = start; for ( ; it != last; ++it) { if( it+1 == last ) break; else if ( (stop + static_cast<T>(1)) == *(it+1) ) stop = *(it+1); else break; } mess << start; if (start != stop) mess << "-" << stop; if (it+1 != last) mess << ","; } return mess.str(); } template<typename T> std::string toString(const std::set<T> &value) { return toString(std::vector<T>(value.begin(), value.end())); } template<> MANTID_KERNEL_DLL std::string toString(const UnitLabel &value) { return value; } //------------------------------------------------------------------------------------------------ /** * Write out the three vectors into a file of type dc 9 * @param step :: parameter to control x-step (starts from zero) * @param Y :: Y column * @param Fname :: Name of the file * @return 0 on success and -ve on failure */ template<template<typename T,typename A> class V,typename T,typename A> int writeFile(const std::string& Fname,const T &step, const V<T,A>& Y) { V<T,A> Ex; // Empty vector V<T,A> X; // Empty vector for(unsigned int i=0;i<Y.size();i++) X.push_back(i*step); return writeFile(Fname,X,Y,Ex); } //------------------------------------------------------------------------------------------------ /** * Write out the three vectors into a file of type dc 9 * @param X :: X column * @param Y :: Y column * @param Fname :: Name of the file * @return 0 on success and -ve on failure */ template<template<typename T,typename A> class V,typename T,typename A> int writeFile(const std::string& Fname,const V<T,A>& X,const V<T,A>& Y) { V<T,A> Ex; // Empty vector/list return writeFile(Fname,X,Y,Ex); // don't need to specific ?? } //------------------------------------------------------------------------------------------------ /** * Write out the three container into a file with * column free-formated data in the form : * - X Y Err * If Err does not exist (or is short) 0.0 is substituted. * @param X :: X column * @param Y :: Y column * @param Err :: Err column * @param Fname :: Name of the file * @return 0 on success and -ve on failure */ template<template<typename T,typename A> class V,typename T,typename A> int writeFile(const std::string& Fname,const V<T,A>& X,const V<T,A>& Y,const V<T,A>& Err) { const size_t Npts(X.size()>Y.size() ? Y.size() : X.size()); const size_t Epts(Npts > Err.size() ? Err.size() : Npts); std::ofstream FX; FX.open(Fname.c_str()); if (!FX.good()) return -1; FX<<"# "<<Npts<<" "<<Epts<<std::endl; FX.precision(10); FX.setf(std::ios::scientific,std::ios::floatfield); typename V<T,A>::const_iterator xPt=X.begin(); typename V<T,A>::const_iterator yPt=Y.begin(); typename V<T,A>::const_iterator ePt=(Epts ? Err.begin() : Y.begin()); // Double loop to include/exclude a short error stack size_t eCount=0; for(;eCount<Epts;eCount++) { FX<<(*xPt)<<" "<<(*yPt)<<" "<<(*ePt)<<std::endl; ++xPt; ++yPt; ++ePt; } for(;eCount<Npts;eCount++) { FX<<(*xPt)<<" "<<(*yPt)<<" 0.0"<<std::endl; ++xPt; ++yPt; } FX.close(); return 0; } //------------------------------------------------------------------------------------------------ /** * Call to read in various values in position x1,x2,x3 from the * line. Note to avoid the dependency on crossSort this needs * to be call IN ORDER * @param Line :: string to read * @param Index :: Indexes to read * @param Out :: OutValues [unchanged if not read] * @retval 0 :: success * @retval -ve on failure. */ template<typename T> int setValues(const std::string& Line,const std::vector<int>& Index,std::vector<T>& Out) { if (Index.empty()) return 0; if(Out.size()!=Index.size()) return -1; // throw ColErr::MisMatch<int>(Index.size(),Out.size(), // "Mantid::Kernel::Strings::setValues"); std::string modLine=Line; std::vector<int> sIndex(Index); // Copy for sorting std::vector<int> OPt(Index.size()); for(unsigned int i=0;i<Index.size();i++) OPt[i]=i; // mathFunc::crossSort(sIndex,OPt); typedef std::vector<int>::const_iterator iVecIter; std::vector<int>::const_iterator sc=sIndex.begin(); std::vector<int>::const_iterator oc=OPt.begin(); int cnt(0); T value; std::string dump; while(sc!=sIndex.end() && *sc<0) { ++sc; ++oc; } while(sc!=sIndex.end()) { if (*sc==cnt) { if (!section(modLine,value)) return static_cast<int>(-1-distance(static_cast<iVecIter>(sIndex.begin()),sc)); // this loop handles repeat units do { Out[*oc]=value; ++sc; ++oc; } while (sc!=sIndex.end() && *sc==cnt); } else { if (!section(modLine,dump)) return static_cast<int>(-1-distance(static_cast<iVecIter>(sIndex.begin()),sc)); } cnt++; // Add only to cnt [sc/oc in while loop] } // Success since loop only gets here if sc is exhaused. return 0; } //----------------------------------------------------------------------------------------------- /** Get a word from a line and strips spaces * * @param in :: stream input * @param consumeEOL :: set to true to remove the new lines at the end of the line * @return a string with the word read in */ std::string getWord( std::istream &in , bool consumeEOL ) { std::string s; char c = 0; if( in.good() ) for( c = static_cast<char>(in.get()) ; c == ' ' && in.good() ; c = static_cast<char>(in.get()) ) {} else return std::string(); if( c == '\n' ) { if( !consumeEOL ) in.putback( c ); return std::string(); } s.push_back( c ); if( in.good() ) for( c = static_cast<char>(in.get()) ; in.good()&&c != ' ' && c != '\n' && c != '\r' ; c = static_cast<char>(in.get()) ) s.push_back( c ); if( ((c == '\n') || (c == '\r')) && !consumeEOL ) in.putback( c ); return s; } //----------------------------------------------------------------------------------------------- /** Read up to the eol * * @param in :: stream input * @param ConsumeEOL :: set to true to remove the new lines at the end of the line */ void readToEndOfLine( std::istream& in , bool ConsumeEOL ) { while( in.good() && getWord( in , false ).length() > 0 ) getWord( in , false ); if( !ConsumeEOL ) return ; getWord( in , true ); } /** * Function parses a path, placed into input string "path" and returns vector of the folders contributed into the path * @param path :: the string containing input path, found in path string, if they are separated by \ or / symbols. * Treats special symbols, if defined in the input string as path-es * returns 0 for empty input string * @param path_components :: holder for the individual folders in the path * used to generate path in hdf file, so the resulting path has to obey hdf constrains; */ size_t split_path(const std::string &path, std::vector<std::string> &path_components) { if(path.empty()){ path_components.resize(0); return 0; } // convert Windows path into the unix one std::string working_path(path); for(size_t i=0;i<path.size();i++){ if(working_path[i]<0x20||working_path[i]>0x7E)working_path[i]='_'; if(working_path[i]=='\\')working_path[i]='/'; if(working_path[i]==' ')working_path[i]='_'; } // path start with relative character, and we need to convert it into full path if(path[0]=='.'){ // get absolute path using working directory as base; Poco::Path absol; absol = absol.absolute(); working_path = absol.toString(Poco::Path::PATH_UNIX)+working_path; } // as poco splt using regular expressions is doing some rubbish, we need to do split manually // code below implements perl split(/\\//,string) commamd. (\\ has been converted to / above) std::list<int64_t> split_pos; split_pos.push_back(-1); size_t path_size = working_path.size(); for(size_t i=0;i<path_size;i++){ if(working_path[i]=='/'){ split_pos.push_back(i); } } split_pos.push_back(path_size); // allocate target vector to keep folder structure and fill it in size_t n_folders = split_pos.size()-1; path_components.resize(n_folders); std::list<int64_t>::iterator it1 = split_pos.begin(); std::list<int64_t>::iterator it2 = it1; ++it2; int64_t ic(0); for(; it2!=split_pos.end();++it2){ std::string folder = working_path.substr(*it1+1,*it2-*it1-1); if(folder.empty()||(folder.size()==1&&folder==".")){ // skip self-references and double slashes; it1=it2; continue; } // reprocess up-references; if(folder==".."){ if(folder.size()!=2)throw(std::invalid_argument("path contains wrong path group")); ic--; if(ic<0)throw(std::invalid_argument("path contains relative references to a folder outside of the seach tree")); it1=it2; continue; } path_components[ic]=folder; ic++; it1=it2; } n_folders=size_t(ic); path_components.resize(n_folders); return n_folders; } /** * Function checks if the candidate is the member of the group * @param group :: vector of string to check * @param candidate :: the string which has to be checked against the group * @returns :: number of the candidate in the input vector of strings if the candidate belongs to the group or -1 if it does not. Returns the number of the first maching entry in the group if there are duplicated entries in the group */ int isMember(const std::vector<std::string> &group, const std::string &candidate) { int num(-1); for(size_t i=0;i<group.size();i++){ if(candidate.compare(group[i])==0){ num = int(i); return num; } } return num; } /** * Parses a number range, e.g. "1,4-9,54-111,3,10", to the vector containing all the elements * within the range. * @param str String to parse * @param elemSep String with characters used to separate elements (',') * @param rangeSep String with characters used to separate range start and end ('-') * @return A vector with all the elements from the range */ std::vector<int> parseRange(const std::string& str, const std::string& elemSep, const std::string& rangeSep) { typedef Poco::StringTokenizer Tokenizer; boost::shared_ptr<Tokenizer> elements; if(elemSep.find(' ') != std::string::npos) { // If element separator contains space character it's a special case, because in that case // it is allowed to have element separator inside a range, e.g. "4 - 5", but not "4,-5" // Space is added so that last empty element of the "1,2,3-" is not ignored and we can // spot the error. Behaviour is changed in Poco 1.5 and this will not be needed. Tokenizer ranges(str + " ", rangeSep, Tokenizer::TOK_TRIM); std::string new_str = join(ranges.begin(), ranges.end(), rangeSep.substr(0,1)); elements = boost::make_shared<Tokenizer>(new_str, elemSep, Tokenizer::TOK_IGNORE_EMPTY | Tokenizer::TOK_TRIM); } else { elements = boost::make_shared<Tokenizer>(str, elemSep, Tokenizer::TOK_IGNORE_EMPTY | Tokenizer::TOK_TRIM); } std::vector<int> result; // Estimation of the resulting number of elements result.reserve(elements->count()); for (Tokenizer::Iterator it = elements->begin(); it != elements->end(); it++) { // See above for the reason space is added Tokenizer rangeElements(*it + " ", rangeSep, Tokenizer::TOK_TRIM); size_t noOfRangeElements = rangeElements.count(); // A single element if(noOfRangeElements == 1) { int element; if(convert(rangeElements[0], element) != 1) throw std::invalid_argument("Invalid element: " + *it); result.push_back(element); } // A pair else if(noOfRangeElements == 2) { int start, end; if(convert(rangeElements[0], start) != 1 || convert(rangeElements[1], end) != 1) throw std::invalid_argument("Invalid range: " + *it); if(start >= end) throw std::invalid_argument("Range boundaries are reversed: " + *it); for(int i = start; i <= end; i++) result.push_back(i); } // Error - e.g. "--"" else { throw std::invalid_argument("Multiple range separators: " + *it); } } return result; } /** * Extract a string until an EOL character is reached. There are 3 scenarios that we need to deal with * 1) Windows-style - CRLF ('\\r\\n'); * 2) Unix-style - LF ('\\n'); * 3) Old MAC style - CR ('\\r'). * This function will give the string preceding any of these sequences * @param is :: The input stream to read from * @param str :: The output string to use to accumulate the line * @returns A reference to the input stream */ std::istream& extractToEOL(std::istream& is, std::string& str) { // Empty the string str = ""; char c('\0'); while( is.get(c) ) { if( c == '\r' ) { c = static_cast<char>(is.peek()); if( c == '\n' ) { //Extract this as well is.get(); } break; } else if( c == '\n') { break; } else { //Accumulate the string str += c; } } return is; } /// \cond TEMPLATE template MANTID_KERNEL_DLL int section(std::string&,double&); template MANTID_KERNEL_DLL int section(std::string&,float&); template MANTID_KERNEL_DLL int section(std::string&,int&); template MANTID_KERNEL_DLL int section(std::string&,std::string&); template MANTID_KERNEL_DLL int sectPartNum(std::string&,double&); template MANTID_KERNEL_DLL int sectPartNum(std::string&,int&); template MANTID_KERNEL_DLL int sectionMCNPX(std::string&,double&); template MANTID_KERNEL_DLL int convert(const std::string&,double&); template MANTID_KERNEL_DLL int convert(const std::string&,float&); template MANTID_KERNEL_DLL int convert(const std::string&,std::string&); template MANTID_KERNEL_DLL int convert(const std::string&,int&); template MANTID_KERNEL_DLL int convert(const std::string&,std::size_t&); template MANTID_KERNEL_DLL int convert(const std::string&,bool&); template MANTID_KERNEL_DLL int convert(const char*,std::string&); template MANTID_KERNEL_DLL int convert(const char*,double&); template MANTID_KERNEL_DLL int convert(const char*,int&); template MANTID_KERNEL_DLL int convert(const char*,std::size_t&); template MANTID_KERNEL_DLL int convert(const char*,bool&); template MANTID_KERNEL_DLL std::string toString(const double &value); template MANTID_KERNEL_DLL std::string toString(const float &value); template MANTID_KERNEL_DLL std::string toString(const int &value); template MANTID_KERNEL_DLL std::string toString(const uint16_t &value); template MANTID_KERNEL_DLL std::string toString(const size_t &value); // Matches uint64_t on Linux 64 & Win 64 #if defined(__APPLE__) || ( defined(_WIN32) && !defined(_WIN64)) || (defined(__GNUC__) && !defined(__LP64__)) // Mac or 32-bit compiler template MANTID_KERNEL_DLL std::string toString(const uint64_t &value); #endif template MANTID_KERNEL_DLL std::string toString(const std::string &value); template MANTID_KERNEL_DLL std::string toString(const std::vector<int> &value); // this block should generate the vector ones as well template MANTID_KERNEL_DLL std::string toString(const std::set<int> &value); template MANTID_KERNEL_DLL std::string toString(const std::set<int16_t> &value); template MANTID_KERNEL_DLL std::string toString(const std::set<size_t> &value); // Matches uint64_t on Linux 64 & Win 64 #if defined(__APPLE__) || ( defined(_WIN32) && !defined(_WIN64)) || (defined(__GNUC__) && !defined(__LP64__)) // Mac or 32-bit compiler template MANTID_KERNEL_DLL std::string toString(const std::set<uint64_t> &value); #endif template MANTID_KERNEL_DLL int convPartNum(const std::string&,double&); template MANTID_KERNEL_DLL int convPartNum(const std::string&,int&); template MANTID_KERNEL_DLL int setValues(const std::string&,const std::vector<int>&,std::vector<double>&); template MANTID_KERNEL_DLL int writeFile(const std::string&,const double&,const std::vector<double>&); template MANTID_KERNEL_DLL int writeFile(const std::string&,const std::vector<double>&,const std::vector<double>&,const std::vector<double>&); template MANTID_KERNEL_DLL int writeFile(const std::string&,const std::vector<double>&,const std::vector<double>&); template MANTID_KERNEL_DLL int writeFile(const std::string&,const std::vector<float>&,const std::vector<float>&); template MANTID_KERNEL_DLL int writeFile(const std::string&,const std::vector<float>&,const std::vector<float>&,const std::vector<float>&); /// \endcond TEMPLATE } // NAMESPACE Strings } // NAMESPACE Kernel } // NAMESPACE Mantid