Mantid
Loading...
Searching...
No Matches
MultiFileNameParser.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
11
15
16#include <boost/algorithm/string.hpp>
17
18#include <numeric>
19#include <regex>
20#include <sstream>
21#include <utility>
22
25// Static constants.
27
28namespace Regexs {
29const std::string INST = "([A-Za-z]+|PG3|pg3)";
30
31const std::string UNDERSCORE = "(_{0,1})";
32const std::string SPACE = "(\\s*)";
33
34const std::string COMMA = "(" + SPACE + "," + SPACE + ")";
35const std::string PLUS = "(" + SPACE + "\\+" + SPACE + ")";
36const std::string MINUS = "(" + SPACE + "\\-" + SPACE + ")";
37const std::string COLON = "(" + SPACE + ":" + SPACE + ")";
38
39const std::string SINGLE = "(" + INST + "*[0-9]+)";
40const std::string RANGE = "(" + SINGLE + COLON + SINGLE + ")";
41const std::string STEP_RANGE = "(" + SINGLE + COLON + SINGLE + COLON + SINGLE + ")";
42const std::string ADD_RANGE = "(" + SINGLE + MINUS + SINGLE + ")";
43const std::string ADD_STEP_RANGE = "(" + SINGLE + MINUS + SINGLE + COLON + SINGLE + ")";
44const std::string SINGLE_OR_STEP_OR_ADD_RANGE = "(" + ADD_STEP_RANGE + "|" + ADD_RANGE + "|" + SINGLE + ")";
45const std::string ADD_LIST = "(" + SINGLE_OR_STEP_OR_ADD_RANGE + "(" + PLUS + SINGLE_OR_STEP_OR_ADD_RANGE + ")+" + ")";
46
47const std::string ANY =
48 "(" + ADD_STEP_RANGE + "|" + ADD_LIST + "|" + ADD_RANGE + "|" + STEP_RANGE + "|" + RANGE + "|" + SINGLE + ")";
49const std::string LIST = "(" + ANY + "(" + COMMA + ANY + ")*" + ")";
50} // namespace Regexs
51
53// Forward declarations.
55
56namespace {
57// Anonymous helper functions.
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 &regexString, const bool caseless = false);
63std::string getMatchingString(const std::string &regexString, const std::string &toParse, const bool caseless = false);
64std::string pad(const unsigned int run, const std::string &instString);
65
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);
69
70// Helper functor.
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);
74};
75
76std::string toString(const RunRangeList &runRangeList);
77std::string accumulateString(std::string output, std::pair<unsigned int, unsigned int> runRange);
78} // namespace
79
81// Scoped, global functions.
83
96std::string suggestWorkspaceName(const std::vector<std::string> &fileNames) {
97 Parser parser;
98 RunRangeList runs;
99
100 // For each file name, parse the run number out of it, and add it to a
101 // RunRangeList.
102 for (const auto &fileName : fileNames) {
103 parser.parse(fileName);
104 runs.addRun(parser.runs()[0][0]);
105 }
106
107 // Return the suggested ws name.
108 return parser.instString() + parser.underscoreString() + toString(runs);
109}
110
112// Comparator class.
114
121bool ReverseCaselessCompare::operator()(const std::string &a, const std::string &b) const {
122 std::string lowerA;
123 lowerA.resize(a.size());
124 std::string lowerB;
125 lowerB.resize(b.size());
126
127 std::transform(a.cbegin(), a.cend(), lowerA.begin(), tolower);
128 std::transform(b.cbegin(), b.cend(), lowerB.begin(), tolower);
129
130 return lowerA > lowerB;
131}
132
134// Public member functions of Parser class.
136
139 : m_runs(), m_fileNames(), m_multiFileName(), m_dirString(), m_instString(), m_underscoreString(), m_runString(),
140 m_extString(), m_validInstNames(), m_compoundLeadExtensions(), m_trimWhiteSpaces(true) {
141 const ConfigServiceImpl &config = ConfigService::Instance();
142
143 const auto facilities = config.getFacilities();
144 for (const auto facility : facilities) {
145 for (const auto &instrument : facility->instruments()) {
146 m_validInstNames.insert(instrument.name());
147 m_validInstNames.insert(instrument.shortName());
148 }
149
150 // Derive compound-extension leads from FileExtensions. For a two-component
151 // entry like ".nxs.h5" the lead is ".nxs"; the parser uses this set in
152 // split() to keep the inner extension out of the file stem. Entries with
153 // a single dot (e.g. ".nxs", "_event.nxs") or more than two dots are
154 // skipped — the parser only models two-component compounds.
155 for (const auto &ext : facility->extensions()) {
156 if (std::count(ext.cbegin(), ext.cend(), '.') != 2)
157 continue;
158 auto lead = ext.substr(0, ext.find_last_of('.'));
159 if (!lead.empty() && lead.front() == '.')
160 m_compoundLeadExtensions.insert(std::move(lead));
161 }
162 }
163}
164
172void Parser::parse(const std::string &multiFileName) {
173 // Clear any contents of the member variables.
174 clear();
175
176 // Set the string to parse.
177 m_multiFileName = multiFileName;
178
179 // Split the string to be parsed into sections, and do some validation.
180 split();
181
182 // Parse the run section into unsigned ints we can use.
184
185 // Set up helper functor.
187
188 // Generate complete file names for each run using helper functor.
189 std::transform(m_runs.begin(), m_runs.end(), std::back_inserter(m_fileNames), generateFileName);
190}
191
203std::vector<std::vector<unsigned int>> Parser::parseMultiRunString(std::string runString) {
204 // If the run string is empty, return no runs.
205 if (runString.empty())
206 return std::vector<std::vector<unsigned int>>();
207
208 // Remove whitespaces if requested.
209 if (trimWhiteSpaces()) {
210 runString.erase(std::remove_if( // ("Erase-remove" idiom.)
211 runString.begin(), runString.end(), isspace),
212 runString.end());
213 }
214 // Only numeric characters, or occurances of plus, minus, comma and colon are
215 // allowed.
216 if (!matchesFully(runString, "([0-9]|\\+|\\-|,|:)+")) {
217 throw std::runtime_error("Non-numeric or otherwise unaccetable character(s) detected.");
218 }
219
220 // Tokenize on commas.
221 std::vector<std::string> tokens;
222 tokens = boost::split(tokens, runString, boost::is_any_of(","));
223
224 // Validate each token.
225 std::for_each(tokens.begin(), tokens.end(), validateToken);
226
227 // Parse each token, accumulate the results, and return them.
228 std::vector<std::vector<unsigned int>> runGroups;
229 for (auto const &token : tokens) {
230 parseToken(runGroups, token);
231 }
232 return runGroups;
233}
234
241
248void Parser::setTrimWhiteSpaces(const bool &setting) { m_trimWhiteSpaces = setting; }
249
251// Private member functions of Parser class.
253
258 m_runs.clear();
259 m_fileNames.clear();
260 m_multiFileName.clear();
261 m_dirString.clear();
262 m_instString.clear();
263 m_underscoreString.clear();
264 m_runString.clear();
265 m_extString.clear();
266}
267
277 if (m_multiFileName.empty())
278 throw std::runtime_error("No file name to parse.");
279
280 // Clear whitespace before getting extentions and directories, if requested.
281 if (trimWhiteSpaces()) {
282 m_multiFileName.erase(std::remove_if( // ("Erase-remove" idiom.)
283 m_multiFileName.begin(), m_multiFileName.end(), isspace),
284 m_multiFileName.end());
285 }
286 // Get the directory, if there is one.
287 const size_t lastSeparator = m_multiFileName.find_last_of("/\\");
288 if (lastSeparator != std::string::npos)
289 m_dirString = m_multiFileName.substr(0, lastSeparator + 1);
290
291 // Get the extension. Compound extensions like ".nxs.h5" are kept whole when
292 // the leading half (".nxs") matches a known compound lead derived from the
293 // facility FileExtensions in Facilities.xml. Otherwise just the final dot's
294 // suffix is taken. This avoids misidentifying stems that contain dots
295 // (e.g. "run.v2.nxs") as compound-extension files.
296 const size_t lastDot = m_multiFileName.find_last_of('.');
297 if (lastDot != std::string::npos && lastDot > m_dirString.size()) {
298 const size_t prevDot = m_multiFileName.find_last_of('.', lastDot - 1);
299 if (prevDot != std::string::npos && prevDot >= m_dirString.size()) {
300 const auto midExt = m_multiFileName.substr(prevDot, lastDot - prevDot);
301 if (m_compoundLeadExtensions.contains(midExt))
302 m_extString = m_multiFileName.substr(prevDot);
303 }
304 if (m_extString.empty())
305 m_extString = m_multiFileName.substr(lastDot);
306 }
307
308 // If the directory contains an instance of a comma, then the string is
309 // a comma separated list of single *full* file names to load.
310 if (std::string::npos != m_dirString.find(','))
311 throw std::runtime_error("Unable to parse.");
312
313 // Slice off the directory and extension.
314 std::string base =
315 m_multiFileName.substr(m_dirString.size(), m_multiFileName.size() - (m_dirString.size() + m_extString.size()));
316
317 if (base.empty())
318 throw std::runtime_error("There does not appear to be any runs present.");
319
320 auto instrumentNameIt = std::find_if(m_validInstNames.cbegin(), m_validInstNames.cend(), [&base](const auto &name) {
321 return matchesFully(base, name + ".*", true);
322 }); // USE CASELESS MATCHES HERE.
323
324 // See if the user has typed in one of the available instrument names.
325 if (instrumentNameIt != m_validInstNames.cend()) {
326 m_instString = getMatchingString("^" + *instrumentNameIt, base, true);
327 }
328
329 // If not, use the default, or throw if we encounter an unrecognisable
330 // non-numeric string.
331 if (m_instString.empty()) {
332 if (base.empty())
333 throw std::runtime_error("There does not appear to be any runs present.");
334
335 if (isdigit(base[0]))
336 m_instString = ConfigService::Instance().getString("default.instrument");
337 else
338 throw std::runtime_error("There does not appear to be a valid instrument name present.");
339 } else {
340 // Chop off instrument name.
341 base = base.substr(m_instString.size(), base.size());
342 }
343
344 if (base.empty())
345 throw std::runtime_error("There does not appear to be any runs present.");
346
347 const auto &instInfo = ConfigService::Instance().getInstrument(m_instString);
348 // why?
349 // m_instString = instInfo.shortName(); // Make sure we're using the shortened
350 // form of the isntrument name.
351
352 if (base.starts_with(instInfo.delimiter())) {
353 // Store the instrument delimiter, and strip it off the start of the string.
354 m_underscoreString = instInfo.delimiter();
355 base = base.substr(m_underscoreString.size(), base.size());
356 }
357
358 // LIST requires at least one run number ([0-9]+) so a base with no digits
359 // can never match. Skip the expensive regex and fail fast.
360 if (base.find_first_of("0123456789") == std::string::npos)
361 throw std::runtime_error("There do not appear to be any runs present.");
362
363 m_runString = getMatchingString("^" + Regexs::LIST, base);
364
365 if (m_runString.size() != base.size()) {
366 throw std::runtime_error("There is an unparsable token present.");
367 }
368}
369
371// Helper functor.
373
381GenerateFileName::GenerateFileName(std::string prefix, std::string suffix, std::string instString)
382 : m_prefix(std::move(prefix)), m_suffix(std::move(suffix)), m_instString(std::move(instString)) {}
383
392std::vector<std::string> GenerateFileName::operator()(const std::vector<unsigned int> &runs) {
393 std::vector<std::string> fileNames;
394
395 std::transform(runs.begin(), runs.end(), std::back_inserter(fileNames),
396 (*this) // Call other overloaded function operator.
397 );
398
399 return fileNames;
400}
401
409std::string GenerateFileName::operator()(const unsigned int run) {
410 std::stringstream fileName;
411
412 fileName << m_prefix << pad(run, m_instString) << m_suffix;
413
414 return fileName.str();
415}
416
418// Public member functions of RunRangeList class.
420
424RunRangeList::RunRangeList() : m_rangeList() {}
425
431void RunRangeList::addRun(const unsigned int run) {
432 // If the run is inside one of the ranges, do nothing.
433 if (std::binary_search(m_rangeList.begin(), m_rangeList.end(), run, RangeContainsRun()))
434 return;
435
436 // Else create a new range, containing a single run, and add it to the list.
437 m_rangeList.emplace(run, run);
438
439 // Now merge any ranges that are adjacent.
440 m_rangeList = std::accumulate(m_rangeList.begin(), m_rangeList.end(),
441 std::set<std::pair<unsigned int, unsigned int>>(), mergeAdjacentRanges);
442}
443
450void RunRangeList::addRunRange(unsigned int from, unsigned int to) {
451 for (; from <= to; ++from)
452 addRun(from);
453}
454
460void RunRangeList::addRunRange(const std::pair<unsigned int, unsigned int> &range) {
461 addRunRange(range.first, range.second);
462}
463
465// Anonymous helper functions.
467
468namespace // anonymous
469{
477void parseToken(std::vector<std::vector<unsigned int>> &parsedRuns, const std::string &token) {
478 std::vector<std::vector<unsigned int>> runs;
479 // Tokenise further on plus.
480 std::vector<std::string> subTokens;
481 boost::split(subTokens, token, boost::is_any_of("+"));
482 std::vector<unsigned int> runsToAdd;
483 for (auto const &subToken : subTokens) {
484 // E.g. "2012".
485 if (matchesFully(subToken, Regexs::SINGLE)) {
486 runsToAdd.emplace_back(std::stoi(subToken));
487 }
488 // E.g. "2012:2020".
489 else if (matchesFully(subToken, Regexs::RANGE)) {
490 // Fill in runs directly.
491 constexpr bool addRuns{false};
492 std::vector<std::string> rangeDetails;
493 rangeDetails.reserve(2);
494 boost::split(rangeDetails, subToken, boost::is_any_of(":"));
495 runs = generateRange(std::stoi(rangeDetails.front()), std::stoi(rangeDetails.back()), 1, addRuns);
496 }
497 // E.g. "2012:2020:4".
498 else if (matchesFully(subToken, Regexs::STEP_RANGE)) {
499 // Fill in runs directly.
500 constexpr bool addRuns{false};
501 std::vector<std::string> rangeDetails;
502 rangeDetails.reserve(3);
503 boost::split(rangeDetails, subToken, boost::is_any_of(":"));
504 runs = generateRange(std::stoi(rangeDetails[0]), std::stoi(rangeDetails[1]), std::stoi(rangeDetails[2]), addRuns);
505 }
506 // E.g. "2012-2020".
507 else if (matchesFully(subToken, Regexs::ADD_RANGE)) {
508 constexpr bool addRuns{true};
509 std::vector<std::string> rangeDetails;
510 rangeDetails.reserve(2);
511 boost::split(rangeDetails, subToken, boost::is_any_of("-"));
512 const auto generated = generateRange(std::stoi(rangeDetails.front()), std::stoi(rangeDetails.back()), 1, addRuns);
513 std::copy(generated.front().cbegin(), generated.front().cend(), back_inserter(runsToAdd));
514 }
515 // E.g. "2012-2020:4".
516 else if (matchesFully(subToken, Regexs::ADD_STEP_RANGE)) {
517 constexpr bool addRuns{true};
518 std::vector<std::string> rangeDetails;
519 rangeDetails.reserve(3);
520 boost::split(rangeDetails, subToken, boost::is_any_of("-:"));
521 const auto generated =
522 generateRange(std::stoi(rangeDetails[0]), std::stoi(rangeDetails[1]), std::stoi(rangeDetails[2]), addRuns);
523 std::copy(generated.front().cbegin(), generated.front().cend(), back_inserter(runsToAdd));
524 } else {
525 // We should never reach here - the validation done on the token
526 // previously should prevent any other possible scenario.
527 assert(false);
528 }
529 }
530 if (!runsToAdd.empty()) {
531 if (!runs.empty()) {
532 // We have either add ranges or step ranges. Never both.
533 throw std::runtime_error("Unable to handle a mixture of add ranges and step ranges");
534 }
535 runs.emplace_back(runsToAdd);
536 }
537 // Add the runs on to the end of parsedRuns, and return it.
538 std::copy(runs.begin(), runs.end(), std::back_inserter(parsedRuns));
539}
540
556std::vector<std::vector<unsigned int>> generateRange(unsigned int const from, unsigned int const to,
557 unsigned int const stepSize, bool const addRuns) {
558 if (stepSize == 0)
559 throw std::runtime_error("Unable to generate a range with a step size of zero.");
560
561 size_t limit;
562 auto limitStr = ConfigService::Instance().getValue<std::string>("loading.multifilelimit");
563 if (!limitStr.has_value() || !Strings::convert(limitStr.value(), limit)) {
564 limit = ConfigService::Instance().getFacility().multiFileLimit();
565 }
566
567 unsigned int const orderedTo = from > to ? from : to;
568 unsigned int const orderedFrom = from > to ? to : from;
569 unsigned int const numberOfFiles = (orderedTo - orderedFrom) / stepSize;
570 if (numberOfFiles > limit) {
571 std::stringstream sstream;
572 sstream << "The range from " << orderedFrom << " to " << orderedTo << " with step " << stepSize
573 << " would generate " << numberOfFiles << " files. "
574 << "This is greater than the current limit of " << limit << ". "
575 << "This limit can be configured in the Mantid.user.properties "
576 "file using the key loading.multifilelimit=200.";
577 throw std::range_error(sstream.str());
578 }
579
580 unsigned int currentRun = from;
581 std::vector<std::vector<unsigned int>> runs;
582
583 // If ascending range
584 if (from <= to) {
585 while (currentRun <= to) {
586 if (addRuns) {
587 if (runs.empty())
588 runs.emplace_back(1, currentRun);
589 else
590 runs.front().emplace_back(currentRun);
591 } else {
592 runs.emplace_back(1, currentRun);
593 }
594
595 currentRun += stepSize;
596 }
597 }
598 // Else descending range
599 else {
600 while (currentRun >= to) {
601 if (addRuns) {
602 if (runs.empty())
603 runs.emplace_back(1, currentRun);
604 else
605 runs.front().emplace_back(currentRun);
606 } else {
607 runs.emplace_back(1, currentRun);
608 }
609
610 // Guard against case where stepSize would take us into negative
611 // numbers (not supported by unsigned ints ...).
612 if (static_cast<int>(currentRun) - static_cast<int>(stepSize) < 0)
613 break;
614
615 currentRun -= stepSize;
616 }
617 }
618
619 return runs;
620}
621
629void validateToken(const std::string &token) {
630 // Each token must be non-empty.
631 if (token.empty())
632 throw std::runtime_error("A comma-separated token is empty.");
633
634 // Each token must begin and end with a numeric character.
635 if (!matchesFully(token, "[0-9].+[0-9]|[0-9]"))
636 throw std::runtime_error("The token \"" + token +
637 "\" is of an incorrect form. Does it begin or "
638 "end with a plus, minus or colon?");
639
640 // Each token must be one of the acceptable forms, i.e. a single run, an added
641 // range of runs, etc.
642 if (!matchesFully(token, Regexs::ANY))
643 throw std::runtime_error("The token \"" + token + "\" is of an incorrect form.");
644}
645
655bool matchesFully(const std::string &stringToMatch, const std::string &regexString, const bool caseless) {
656 const auto flags = caseless ? std::regex::ECMAScript | std::regex::icase : std::regex::ECMAScript;
657 const std::regex regex("^(" + regexString + "$)", flags);
658 return std::regex_match(stringToMatch, regex);
659}
660
670std::string getMatchingString(const std::string &regexString, const std::string &toParse, const bool caseless) {
671 const auto flags = caseless ? std::regex::ECMAScript | std::regex::icase : std::regex::ECMAScript;
672 const std::regex regex(regexString, flags);
673
674 std::sregex_iterator it(toParse.begin(), toParse.end(), regex);
675 if (it == std::sregex_iterator())
676 return "";
677
678 return it->str();
679}
680
690std::string pad(const unsigned int run, const std::string &instString) {
691 InstrumentInfo const instInfo = ConfigService::Instance().getInstrument(instString);
692 std::string prefix;
693 if (!instInfo.facility().noFilePrefix())
694 prefix = instInfo.filePrefix(run) + instInfo.delimiter();
695 unsigned int padLength = instInfo.zeroPadding(run);
696 std::string runStr = std::to_string(run);
697 if (runStr.size() < padLength)
698 runStr.insert(0, padLength - runStr.size(), '0');
699 else if (padLength > 0 && runStr.size() > padLength)
700 throw std::runtime_error("Could not parse run number \"" + runStr +
701 "\" since the instrument run number length required is " + std::to_string(padLength));
702 runStr.insert(0, prefix);
703 return runStr;
704}
705
713bool RangeContainsRun::operator()(const std::pair<unsigned int, unsigned int> &range, const unsigned int run) {
714 return range.second < run;
715}
716bool RangeContainsRun::operator()(const unsigned int run, const std::pair<unsigned int, unsigned int> &range) {
717 return run < range.first;
718}
719
729std::set<std::pair<unsigned int, unsigned int>>
730mergeAdjacentRanges(std::set<std::pair<unsigned int, unsigned int>> ranges,
731 const std::pair<unsigned int, unsigned int> &range) {
732 // If ranges is empty, just insert the new range.
733 if (ranges.empty()) {
734 ranges.insert(range);
735 }
736 // Else there are already some ranges present ...
737 else {
738 // ... if the last one is adjacent to the new range, merge the two.
739 if (ranges.rbegin()->second + 1 == range.first) {
740 unsigned int from = ranges.rbegin()->first;
741 unsigned int to = range.second;
742 std::pair<unsigned int, unsigned int> temp(from, to);
743
744 ranges.erase(--ranges.end(), ranges.end());
745 ranges.insert(temp);
746 }
747 // ... else just insert it.
748 else {
749 ranges.insert(range);
750 }
751 }
752 return ranges;
753}
754
765std::string accumulateString(std::string output, std::pair<unsigned int, unsigned int> runRange) {
766 if (!output.empty())
767 output += "_and_";
768
769 if (runRange.first == runRange.second)
770 output += std::to_string(runRange.first);
771 else
772 output += std::to_string(runRange.first) + "_to_" + std::to_string(runRange.second);
773
774 return output;
775}
776
784std::string toString(const RunRangeList &runRangeList) {
785 std::set<std::pair<unsigned int, unsigned int>> runRanges = runRangeList.rangeList();
786
787 // For each run range (pair of unsigned ints), call accumulateString and
788 // return the accumulated result.
789 return std::accumulate(runRanges.begin(), runRanges.end(), std::string(), accumulateString);
790}
791
792} // anonymous namespace
793
794} // namespace Mantid::Kernel::MultiFileNameParsing
std::string name
Definition Run.cpp:60
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 ...
const std::string & runString() const
Return the parsed run 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::vector< std::vector< unsigned int > > m_runs
A vector of vectors of the parsed runs.
std::set< std::string > m_compoundLeadExtensions
Compound-extension leads derived from Facilities.xml.
void split()
Split the string to parse into its component parts.
std::set< std::string, ReverseCaselessCompare > m_validInstNames
All the valid instrument names.
const std::string & underscoreString() const
Return the parsed underscore string.
const std::vector< std::vector< unsigned int > > & runs() const
Return the vector of vectors of parsed file names.
bool trimWhiteSpaces() const
Return the setting for trimming whitespaces in run string.
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.
const std::string & instString() const
Return the parsed instrument string.
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.
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.
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.
Definition Strings.cpp:696
std::string toString(const T &value)
Convert values to strings.
MortonT pad(IntT)
Pad an integer with a given number of padding bits.
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)