19#include <boost/algorithm/string.hpp>
20#include <boost/regex.hpp>
29const std::string
INST =
"([A-Za-z]+|PG3|pg3)";
32const std::string
SPACE =
"(\\s*)";
47const std::string
ANY =
58void parseToken(std::vector<std::vector<unsigned int>> &parsedRuns,
const std::string &token);
59std::vector<std::vector<unsigned int>> generateRange(
const unsigned int from,
const unsigned int to,
60 const unsigned int stepSize,
const bool addRuns);
61void validateToken(
const std::string &token);
62bool matchesFully(
const std::string &stringToMatch,
const std::string ®exString,
const bool caseless =
false);
63std::string getMatchingString(
const std::string ®exString,
const std::string &toParse,
const bool caseless =
false);
64std::string pad(
const unsigned int run,
const std::string &instString);
66std::set<std::pair<unsigned int, unsigned int>> &
67mergeAdjacentRanges(std::set<std::pair<unsigned int, unsigned int>> &ranges,
68 const std::pair<unsigned int, unsigned int> &range);
71struct RangeContainsRun {
72 bool operator()(
const std::pair<unsigned int, unsigned int> &range,
const unsigned int run);
73 bool operator()(
const unsigned int run,
const std::pair<unsigned int, unsigned int> &range);
76std::string toString(
const RunRangeList &runRangeList);
77std::string &accumulateString(std::string &output, std::pair<unsigned int, unsigned int> runRange);
102 for (
const auto &fileName : fileNames) {
103 parser.
parse(fileName);
123 lowerA.resize(a.size());
125 lowerB.resize(b.size());
127 std::transform(a.cbegin(), a.cend(), lowerA.begin(), tolower);
128 std::transform(b.cbegin(), b.cend(), lowerB.begin(), tolower);
130 return lowerA > lowerB;
139 : m_runs(), m_fileNames(), m_multiFileName(), m_dirString(), m_instString(), m_underscoreString(), m_runString(),
140 m_extString(), m_validInstNames(), m_trimWhiteSpaces(true) {
144 for (
const auto facility : facilities) {
145 const std::vector<InstrumentInfo> instruments = facility->instruments();
147 for (
const auto &instrument : instruments) {
195 return std::vector<std::vector<unsigned int>>();
205 if (!matchesFully(
runString,
"([0-9]|\\+|\\-|,|:)+")) {
206 throw std::runtime_error(
"Non-numeric or otherwise unaccetable character(s) detected.");
210 std::vector<std::string> tokens;
211 tokens = boost::split(tokens,
runString, boost::is_any_of(
","));
214 std::for_each(tokens.begin(), tokens.end(), validateToken);
217 std::vector<std::vector<unsigned int>> runGroups;
218 for (
auto const &token : tokens) {
219 parseToken(runGroups, token);
267 throw std::runtime_error(
"No file name to parse.");
280 if (lastDot != std::string::npos)
285 if (lastSeparator != std::string::npos)
291 throw std::runtime_error(
"Unable to parse.");
298 throw std::runtime_error(
"There does not appear to be any runs present.");
301 return matchesFully(base, name +
".*", true);
306 m_instString = getMatchingString(
"^" + *instrumentNameIt, base,
true);
313 throw std::runtime_error(
"There does not appear to be any runs present.");
315 if (isdigit(base[0]))
318 throw std::runtime_error(
"There does not appear to be a valid instrument name present.");
325 throw std::runtime_error(
"There does not appear to be any runs present.");
332 if (boost::starts_with(base, instInfo.delimiter())) {
341 throw std::runtime_error(
"There is an unparsable token present.");
357 : m_prefix(
std::move(prefix)), m_suffix(
std::move(suffix)), m_instString(
std::move(instString)) {}
368 std::vector<std::string> fileNames;
370 std::transform(runs.begin(), runs.end(), std::back_inserter(fileNames),
385 std::stringstream fileName;
389 return fileName.str();
416 std::set<std::pair<unsigned int, unsigned int>>(), mergeAdjacentRanges);
426 for (; from <= to; ++from)
452void parseToken(std::vector<std::vector<unsigned int>> &parsedRuns,
const std::string &token) {
453 std::vector<std::vector<unsigned int>> runs;
455 std::vector<std::string> subTokens;
456 boost::split(subTokens, token, boost::is_any_of(
"+"));
457 std::vector<unsigned int> runsToAdd;
458 for (
auto const &subToken : subTokens) {
461 runsToAdd.emplace_back(std::stoi(subToken));
466 constexpr bool addRuns{
false};
467 std::vector<std::string> rangeDetails;
468 rangeDetails.reserve(2);
469 boost::split(rangeDetails, subToken, boost::is_any_of(
":"));
470 runs = generateRange(std::stoi(rangeDetails.front()), std::stoi(rangeDetails.back()), 1, addRuns);
475 constexpr bool addRuns{
false};
476 std::vector<std::string> rangeDetails;
477 rangeDetails.reserve(3);
478 boost::split(rangeDetails, subToken, boost::is_any_of(
":"));
479 runs = generateRange(std::stoi(rangeDetails[0]), std::stoi(rangeDetails[1]), std::stoi(rangeDetails[2]), addRuns);
483 constexpr bool addRuns{
true};
484 std::vector<std::string> rangeDetails;
485 rangeDetails.reserve(2);
486 boost::split(rangeDetails, subToken, boost::is_any_of(
"-"));
487 const auto generated = generateRange(std::stoi(rangeDetails.front()), std::stoi(rangeDetails.back()), 1, addRuns);
488 std::copy(generated.front().cbegin(), generated.front().cend(), back_inserter(runsToAdd));
492 constexpr bool addRuns{
true};
493 std::vector<std::string> rangeDetails;
494 rangeDetails.reserve(3);
495 boost::split(rangeDetails, subToken, boost::is_any_of(
"-:"));
496 const auto generated =
497 generateRange(std::stoi(rangeDetails[0]), std::stoi(rangeDetails[1]), std::stoi(rangeDetails[2]), addRuns);
498 std::copy(generated.front().cbegin(), generated.front().cend(), back_inserter(runsToAdd));
505 if (!runsToAdd.empty()) {
508 throw std::runtime_error(
"Unable to handle a mixture of add ranges and step ranges");
510 runs.emplace_back(runsToAdd);
513 std::copy(runs.begin(), runs.end(), std::back_inserter(parsedRuns));
531std::vector<std::vector<unsigned int>> generateRange(
unsigned int const from,
unsigned int const to,
532 unsigned int const stepSize,
bool const addRuns) {
534 throw std::runtime_error(
"Unable to generate a range with a step size of zero.");
538 if (!limitStr.is_initialized() || !
Strings::convert(limitStr.get(), limit)) {
542 unsigned int const orderedTo = from > to ? from : to;
543 unsigned int const orderedFrom = from > to ? to : from;
544 unsigned int const numberOfFiles = (orderedTo - orderedFrom) / stepSize;
545 if (numberOfFiles > limit) {
546 std::stringstream sstream;
547 sstream <<
"The range from " << orderedFrom <<
" to " << orderedTo <<
" with step " << stepSize
548 <<
" would generate " << numberOfFiles <<
" files. "
549 <<
"This is greater than the current limit of " << limit <<
". "
550 <<
"This limit can be configured in the Mantid.user.properties "
551 "file using the key loading.multifilelimit=200.";
552 throw std::range_error(sstream.str());
555 unsigned int currentRun = from;
556 std::vector<std::vector<unsigned int>> runs;
560 while (currentRun <= to) {
563 runs.emplace_back(1, currentRun);
565 runs.front().emplace_back(currentRun);
567 runs.emplace_back(1, currentRun);
570 currentRun += stepSize;
575 while (currentRun >= to) {
578 runs.emplace_back(1, currentRun);
580 runs.front().emplace_back(currentRun);
582 runs.emplace_back(1, currentRun);
587 if (
static_cast<int>(currentRun) -
static_cast<int>(stepSize) < 0)
590 currentRun -= stepSize;
604void validateToken(
const std::string &token) {
607 throw std::runtime_error(
"A comma-separated token is empty.");
610 if (!matchesFully(token,
"[0-9].+[0-9]|[0-9]"))
611 throw std::runtime_error(
"The token \"" + token +
612 "\" is of an incorrect form. Does it begin or "
613 "end with a plus, minus or colon?");
618 throw std::runtime_error(
"The token \"" + token +
"\" is of an incorrect form.");
630bool matchesFully(
const std::string &stringToMatch,
const std::string ®exString,
const bool caseless) {
634 regex = boost::regex(
"^(" + regexString +
"$)", boost::regex::icase);
636 regex = boost::regex(
"^(" + regexString +
"$)");
638 return boost::regex_match(stringToMatch, regex);
650std::string getMatchingString(
const std::string ®exString,
const std::string &toParse,
const bool caseless) {
653 regex = boost::regex(regexString, boost::regex::icase);
655 regex = boost::regex(regexString);
658 boost::sregex_iterator it(toParse.begin(), toParse.end(), regex);
660 if (it == boost::sregex_iterator())
675std::string
pad(
const unsigned int run,
const std::string &instString) {
678 if (!instInfo.facility().noFilePrefix())
679 prefix = instInfo.filePrefix(run) + instInfo.delimiter();
680 unsigned int padLength = instInfo.zeroPadding(run);
682 if (runStr.size() < padLength)
683 runStr.insert(0, padLength - runStr.size(),
'0');
684 else if (padLength > 0 && runStr.size() > padLength)
685 throw std::runtime_error(
"Could not parse run number \"" + runStr +
686 "\" since the instrument run number length required is " +
std::to_string(padLength));
687 runStr.insert(0, prefix);
698bool RangeContainsRun::operator()(
const std::pair<unsigned int, unsigned int> &range,
const unsigned int run) {
699 return range.second < run;
701bool RangeContainsRun::operator()(
const unsigned int run,
const std::pair<unsigned int, unsigned int> &range) {
702 return run < range.first;
714std::set<std::pair<unsigned int, unsigned int>> &
715mergeAdjacentRanges(std::set<std::pair<unsigned int, unsigned int>> &ranges,
716 const std::pair<unsigned int, unsigned int> &range) {
718 if (ranges.empty()) {
719 ranges.insert(range);
724 if (ranges.rbegin()->second + 1 == range.first) {
725 unsigned int from = ranges.rbegin()->first;
726 unsigned int to = range.second;
727 std::pair<unsigned int, unsigned int> temp(from, to);
729 ranges.erase(--ranges.end(), ranges.end());
734 ranges.insert(range);
750std::string &accumulateString(std::string &output, std::pair<unsigned int, unsigned int> runRange) {
754 if (runRange.first == runRange.second)
769std::string
toString(
const RunRangeList &runRangeList) {
770 std::set<std::pair<unsigned int, unsigned int>> runRanges = runRangeList.rangeList();
774 return std::accumulate(runRanges.begin(), runRanges.end(), std::string(), accumulateString);
The ConfigService class provides a simple facade to access the Configuration functionality of the Man...
const std::vector< FacilityInfo * > getFacilities() const
Get the list of facilities.
A functor that generates a vector of file names from the given vector of runs, and other state passed...
std::string m_instString
String that identifies the instrument.
std::string m_prefix
String that prefixes any generated file names.
GenerateFileName(std::string prefix, std::string suffix, std::string instString)
Constructor.
std::vector< std::string > operator()(const std::vector< unsigned int > &runs)
Overloaded function operator that generates a vector of file names from a vector of runs.
std::string m_suffix
String that suffixes any generated file names.
This class takes a string representing multiple files and parses it into a vector of vectors of file ...
std::string runString() const
Return the parsed run string.
std::vector< std::vector< unsigned int > > runs() const
Return the vector of vectors of parsed file names.
std::string underscoreString() const
Return the parsed underscore string.
std::string m_multiFileName
The given string to parse.
std::vector< std::vector< std::string > > m_fileNames
A vector of vectors of the parsed file names.
std::vector< std::vector< unsigned int > > parseMultiRunString(std::string runString)
Parses a string consisting of only run number info, into a vector of vector of run numbers.
std::string instString() const
Return the parsed instrument string.
std::vector< std::vector< unsigned int > > m_runs
A vector of vectors of the parsed runs.
std::string m_underscoreString
void split()
Split the string to parse into its component parts.
std::set< std::string, ReverseCaselessCompare > m_validInstNames
All the valid instrument names.
bool trimWhiteSpaces() const
Return the setting for trimming whitespaces in run string.
void clear()
Clear all member variables.
bool m_trimWhiteSpaces
Flag to determine if string input should be trimmed of whitespace.
void setTrimWhiteSpaces(const bool &setting)
Set the flag for trimming whitespaces in run string.
std::string m_dirString
The various sections of the given string to parse.
void parse(const std::string &multiFileName)
Parse the given multiFileNameString.
bool operator()(const std::string &a, const std::string &b) const
Comparator for the set that holds instrument names in Parser.
A class that holds a list of ranges of runs.
RunRangeList()
Constructor.
std::set< std::pair< unsigned int, unsigned int > > m_rangeList
A set of pairs of unsigned ints, where each pair represents a range of runs.
void addRunRange(const unsigned int from, const unsigned int to)
Add a range of runs.
void addRun(const unsigned int run)
Add a run to the list of run ranges.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
const std::string ADD_STEP_RANGE
const std::string SINGLE_OR_STEP_OR_ADD_RANGE
const std::string ADD_RANGE
const std::string ADD_LIST
const std::string UNDERSCORE
const std::string STEP_RANGE
MANTID_KERNEL_DLL std::string suggestWorkspaceName(const std::vector< std::string > &fileNames)
Suggests a workspace name, given a vector of file names.
int convert(const std::string &A, T &out)
Convert a string into a number.
std::string toString(const T &value)
Convert a number to a string.
MortonT pad(IntT)
Pad an integer with a given number of padding bits.
std::string to_string(const wide_integer< Bits, Signed > &n)