1 /* 2 This file is part of the BOLT-LMM linear mixed model software package 3 developed by Po-Ru Loh. Copyright (C) 2014-2019 Harvard University. 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <vector> 20 #include <string> 21 #include <cstdlib> 22 #include <cstdio> 23 #include <iostream> 24 #include <sstream> 25 #include <sys/types.h> // uint 26 27 #include "StringUtils.hpp" 28 29 namespace StringUtils { 30 using std::vector; 31 using std::string; 32 using std::cout; 33 using std::cerr; 34 using std::endl; 35 stoi(const string & s)36 int stoi(const string &s) { 37 int i; 38 if (sscanf(s.c_str(), "%d", &i) == 0) { 39 cerr << "ERROR: Could not parse integer from string: " << s << endl; 40 exit(1); 41 } 42 return i; 43 } stod(const string & s)44 double stod(const string &s) { 45 double d; 46 sscanf(s.c_str(), "%lf", &d); 47 return d; 48 } itos(int i)49 string itos(int i) { 50 std::ostringstream oss; 51 oss << i; 52 return oss.str(); 53 } findDelimiters(const string & s,const string & c)54 string findDelimiters(const string &s, const string &c) { 55 string delims; 56 for (uint p = 0; p < s.length(); p++) 57 if (c.find(s[p], 0) != string::npos) 58 delims += s[p]; 59 return delims; 60 } 61 // will not return blanks tokenizeMultipleDelimiters(const string & s,const string & c)62 vector <string> tokenizeMultipleDelimiters(const string &s, const string &c) 63 { 64 uint p = 0; 65 vector <string> ans; 66 string tmp; 67 while (p < s.length()) { 68 tmp = ""; 69 while (p < s.length() && c.find(s[p], 0) != string::npos) 70 p++; 71 while (p < s.length() && c.find(s[p], 0) == string::npos) { 72 tmp += s[p]; 73 p++; 74 } 75 if (tmp != "") 76 ans.push_back(tmp); 77 } 78 return ans; 79 } 80 rangeErrorExit(const string & str,const string & delims)81 void rangeErrorExit(const string &str, const string &delims) { 82 cerr << "ERROR: Invalid delimiter sequence for specifying range: " << endl; 83 cerr << " Template string: " << str << endl; 84 cerr << " Delimiter sequence found: " << delims << endl; 85 cerr << "Range in must have format {start:end} with no other " << RANGE_DELIMS 86 << " chars" << endl; 87 exit(1); 88 } 89 90 // basic range template: expand "{start:end}" to vector <string> with one entry per range element 91 // if end==start-1, will return empty expandRangeTemplate(const string & str)92 vector <string> expandRangeTemplate(const string &str) { 93 vector <string> ret; 94 string delims = findDelimiters(str, RANGE_DELIMS); 95 if (delims.empty()) 96 ret.push_back(str); 97 else if (delims == RANGE_DELIMS) { 98 vector <string> tokens = tokenizeMultipleDelimiters(str, RANGE_DELIMS); 99 for (int i = 0; i < (int) str.size(); i++) 100 if (str[i] == ':' && (str[i-1] == '{' || str[i+1] == '}')) 101 rangeErrorExit(str, delims); 102 int startInd = (str[0] != RANGE_DELIMS[0]), endInd = startInd+1; 103 string prefix, suffix; 104 if (str[0] != RANGE_DELIMS[0]) prefix = tokens[0]; 105 if (str[str.length()-1] != RANGE_DELIMS[2]) suffix = tokens.back(); 106 int start = StringUtils::stoi(tokens[startInd]), end = StringUtils::stoi(tokens[endInd]); 107 if (start > end+1 || end > start+1000000) { 108 cerr << "ERROR: Invalid range in template string: " << str << endl; 109 cerr << " Start: " << start << endl; 110 cerr << " End: " << end << endl; 111 exit(1); 112 } 113 for (int i = start; i <= end; i++) 114 ret.push_back(prefix + itos(i) + suffix); 115 } 116 else 117 rangeErrorExit(str, delims); 118 return ret; 119 } 120 expandRangeTemplates(const vector<string> & rangeTemplates)121 vector <string> expandRangeTemplates(const vector <string> &rangeTemplates) { 122 vector <string> expanded; 123 for (uint i = 0; i < rangeTemplates.size(); i++) { 124 vector <string> range = expandRangeTemplate(rangeTemplates[i]); 125 expanded.insert(expanded.end(), range.begin(), range.end()); 126 } 127 return expanded; 128 } 129 } 130