diff --git a/Code/Mantid/MantidPlot/CMakeLists.txt b/Code/Mantid/MantidPlot/CMakeLists.txt index 8a3b45f4a3d068da13488359f155d3c27d09bd86..0b3329a562454ed87dafa0434c2e70d5fe01af70 100644 --- a/Code/Mantid/MantidPlot/CMakeLists.txt +++ b/Code/Mantid/MantidPlot/CMakeLists.txt @@ -129,6 +129,7 @@ set ( QTIPLOT_SRCS src/ApplicationWindow.cpp src/TiledWindow.cpp src/TitlePicker.cpp src/TranslateCurveTool.cpp + src/TSVSerialiser.cpp src/UserFunction.cpp src/VectorCurve.cpp src/origin/OPJFile.cpp @@ -372,6 +373,7 @@ set ( QTIPLOT_HDRS src/ApplicationWindow.h src/TiledWindow.h src/TitlePicker.h src/TranslateCurveTool.h + src/TSVSerialiser.h src/UserFunction.h src/VectorCurve.h src/analysis/fft2D.h diff --git a/Code/Mantid/MantidPlot/src/TSVSerialiser.cpp b/Code/Mantid/MantidPlot/src/TSVSerialiser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca8d736ea623c887c82f584ce3f900adb3e3f833 --- /dev/null +++ b/Code/Mantid/MantidPlot/src/TSVSerialiser.cpp @@ -0,0 +1,234 @@ +#include "TSVSerialiser.h" + +#include "MantidKernel/Logger.h" + +#include <boost/algorithm/string.hpp> +#include <boost/regex.hpp> +#include <sstream> + +namespace +{ + Mantid::Kernel::Logger g_log("TSVSerialiser"); +} + +TSVSerialiser::TSVSerialiser() : m_curIndex(0) +{ +} + +TSVSerialiser::TSVSerialiser(std::string lines) +{ + parseLines(lines); +} + +void TSVSerialiser::parseLines(std::string lines) +{ + std::vector<std::string> lineVec; + boost::split(lineVec, lines, boost::is_any_of("\n")); + + //Clear out any old data. + m_lines.clear(); + m_sections.clear(); + + boost::regex valueLineRegex("([a-zA-Z0-9]+)\\b.*"); + boost::regex closedSectionRegex("<([a-zA-Z0-9]+)>(.*)</\\1>"); + boost::regex openSectionRegex("<([a-zA-Z0-9]+)>(.*)"); + + for(auto lineIt = lineVec.begin(); lineIt != lineVec.end(); ++lineIt) + { + std::string line = *lineIt; + + if(line.length() == 0) + continue; + + //Stores matched sections of a regex + boost::smatch matches; + + //Check if this is a value line + if(boost::regex_match(line, matches, valueLineRegex)) + { + std::string name = matches[1].str(); + + m_lines[name].push_back(line); + + g_log.information() << "found value line with name '" << name << "'" << std::endl; + continue; + } + + //Look for lines which open and close a section in one line: <section>data</section> + if(boost::regex_match(line, matches, closedSectionRegex)) + { + std::string name = matches[1].str(); + std::string contents = matches[2].str(); + + m_sections[name].push_back(contents); + + g_log.information() << "found closed section '" << name << "' with contents='" << contents << "'" << std::endl; + continue; + } + + //Check if this is the start of a multiline section, if so, consume the whole section. + if(boost::regex_match(line, matches, openSectionRegex)) + { + std::stringstream sectionSS; + + std::string name = matches[1].str(); + std::string firstLine = matches[2].str(); + + //firstLine exists because of a legacy edgecase: the <folder> section keeps values on the same line as + //the opening tag, so we have to be able to read that. + if(firstLine.length() > 0) + sectionSS << firstLine << "\n"; + + std::stringstream openSS; + openSS << "<" << name << ">.*"; + boost::regex openRegex(openSS.str()); + + std::stringstream closeSS; + closeSS << "</" << name << ">"; + boost::regex closeRegex(closeSS.str()); + + //Next line, to begin parsing + lineIt++; + + //Search for opening and closing tags, counting depth and building the section string. + for(int depth = 1; depth > 0 && lineIt != lineVec.end(); ++lineIt) + { + line = *lineIt; + //Are we going down? + if(boost::regex_match(line, openRegex)) + { + depth++; + } else if(boost::regex_match(line, closeRegex)) + { + depth--; + } + + if(depth > 0) + sectionSS << line << "\n"; + } + + //Back to start of next line; + lineIt--; + + std::string sectionStr = sectionSS.str(); + + //We drop the last character because it's a spare newline + if(sectionStr.size() > 0) + sectionStr.resize(sectionStr.size() - 1); + + m_sections[name].push_back(sectionStr); + + g_log.information() << "read <" << name << ">:\n---------------------------\n" << sectionSS.str() << "----------------------------" << std::endl; + continue; + } + + //If we've made it here then we don't know what kind of line this is. + g_log.error() << "Unable to identify line in TSVSerialiser::parseLines(): '" << line << "'" << std::endl; + } +} + +bool TSVSerialiser::hasLine(std::string name) const +{ + return ( m_lines.find(name) != m_lines.end() ); +} + +bool TSVSerialiser::hasSection(std::string name) const +{ + return ( m_sections.find(name) != m_sections.end() ); +} + +std::vector<std::string> TSVSerialiser::values(std::string name, size_t i) const +{ + //Select correct line with lineAsString, parse it, then return values + std::vector<std::string> ret; + + std::string line = lineAsString(name, i); + boost::split(ret, line, boost::is_any_of("\t")); + + return ret; +} + +std::vector<std::string> TSVSerialiser::sections(std::string name) const +{ + if(!hasSection(name)) + return std::vector<std::string>(); + + return m_sections.at(name); +} + +std::string TSVSerialiser::lineAsString(const std::string name, const size_t i) const +{ + if(!hasLine(name)) + return ""; + + auto lines = m_lines.at(name); + + return lines[i]; +} + +bool TSVSerialiser::selectLine(std::string name, const size_t i) +{ + if(!hasLine(name)) + return false; + + if(i >= m_lines[name].size()) + return false; + + m_curValues = values(name, i); + m_curIndex = 1; //1 because we want to start on the values, not the name + return true; +} + +int TSVSerialiser::asInt(const size_t i) const +{ + if(i >= m_curValues.size()) + return 0; + + std::string valStr = m_curValues.at(i); + + std::stringstream valSS(valStr); + int ret; + valSS >> ret; + + return ret; +} + +double TSVSerialiser::asDouble(const size_t i) const +{ + if(i >= m_curValues.size()) + return 0.00; + + std::string valStr = m_curValues.at(i); + + std::stringstream valSS(valStr); + double ret; + valSS >> ret; + + return ret; +} + +std::string TSVSerialiser::asString(const size_t i) const +{ + if(i >= m_curValues.size()) + return ""; + + return m_curValues.at(i); +} + +TSVSerialiser& TSVSerialiser::operator>>(int& val) +{ + val = asInt(m_curIndex++); + return *this; +} + +TSVSerialiser& TSVSerialiser::operator>>(double& val) +{ + val = asDouble(m_curIndex++); + return *this; +} + +TSVSerialiser& TSVSerialiser::operator>>(std::string& val) +{ + val = asString(m_curIndex++); + return *this; +} diff --git a/Code/Mantid/MantidPlot/src/TSVSerialiser.h b/Code/Mantid/MantidPlot/src/TSVSerialiser.h new file mode 100644 index 0000000000000000000000000000000000000000..332959d40f89ad7d8e924d34f19b1e76ef90fa2c --- /dev/null +++ b/Code/Mantid/MantidPlot/src/TSVSerialiser.h @@ -0,0 +1,68 @@ +#ifndef MANTID_TSVSERIALISER_H_ +#define MANTID_TSVSERIALISER_H_ + +#include <map> +#include <string> +#include <vector> + +/** Parses the formatting used in MantidPlot project files + + @author Harry Jeffery, ISIS, RAL + @date 23/07/2014 + + Copyright © 2007-2014 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid 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. + + Mantid 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://github.com/mantidproject/mantid> +*/ +class TSVSerialiser +{ +public: + + TSVSerialiser(); + + TSVSerialiser(std::string lines); + + void parseLines(std::string lines); + + bool hasLine(const std::string name) const; + bool hasSection(const std::string name) const; + + std::vector<std::string> values(const std::string name, const size_t i = 0) const; + std::vector<std::string> sections(const std::string name) const; + + std::string lineAsString(const std::string name, const size_t i = 0) const; + + bool selectLine(const std::string name, const size_t i = 0); + + int asInt(const size_t i) const; + double asDouble(const size_t i) const; + std::string asString(const size_t i) const; + + TSVSerialiser& operator>>(int& val); + TSVSerialiser& operator>>(double& val); + TSVSerialiser& operator>>(std::string& val); + +private: + std::map<std::string,std::vector<std::string> > m_sections; + std::map<std::string,std::vector<std::string> > m_lines; + + std::vector<std::string> m_curValues; + int m_curIndex; +}; + +#endif