bpp-core3  3.0.0
KeyvalTools.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: The Bio++ Development Group
2 //
3 // SPDX-License-Identifier: CECILL-2.1
4 
5 #include "KeyvalTools.h"
7 
8 // From the STL:
9 #include <memory>
10 
11 using namespace bpp;
12 using namespace std;
13 
14 void KeyvalTools::singleKeyval(const std::string& desc, std::string& key, std::string& val, const std::string& split)
15 {
16  string::size_type i = desc.find(split);
17  if (i == string::npos)
18  throw KeyvalException("Bad syntax! keyval should be of the form 'key" + split + "=value', found '" + desc + "'.");
19  key = desc.substr(0, i);
20  val = desc.substr(i + 1);
21 }
22 
23 void KeyvalTools::multipleKeyvals(const std::string& desc, std::map<std::string, std::string>& keyvals, const std::string& split, bool nested)
24 {
25  unique_ptr<StringTokenizer> st;
26  if (nested)
27  st.reset(new NestedStringTokenizer(desc, "(", ")", split));
28  else
29  st.reset(new StringTokenizer(desc, split));
30  string key, val;
31  vector<string> tokens;
32  // Check tokens:
33  string token;
34  while (st->hasMoreToken())
35  {
36  token = st->nextToken();
37  if (token == "=")
38  {
39  // We need to merge the next token with the last one:
40  if (tokens.size() == 0)
41  throw KeyvalException("Invalid syntax, found '=' without argument name.");
42  if (!st->hasMoreToken())
43  throw KeyvalException("Invalid syntax, found '=' without argument value.");
44  string nextToken = st->nextToken();
45  if (nextToken == "=")
46  throw KeyvalException("Invalid syntax, found a double '='.");
47  tokens[tokens.size() - 1] += "=" + nextToken;
48  }
49  else
50  {
51  tokens.push_back(token);
52  }
53  }
54  for (vector<string>::iterator it = tokens.begin(); it != tokens.end(); it++)
55  {
56  singleKeyval(*it, key, val);
59  keyvals[key] = val;
60  }
61 }
62 
63 std::string KeyvalTools::changeKeyvals(const std::string& desc, const std::map<std::string, std::string>& newkeyvals, const std::string& split, bool nested)
64 {
65  string::size_type begin = desc.find_first_of("(");
66  string::size_type end = desc.find_last_of(")");
67 
68  if (begin == string::npos && end == string::npos)
69  {
70  // Empty procedure:
71  return desc;
72  }
73  if (begin == string::npos && end != string::npos)
74  throw KeyvalException("Bad keyval procedure, missing opening parenthesis.");
75  if (begin == string::npos && end != string::npos)
76  throw KeyvalException("Bad keyval procedure, missing closing parenthesis.");
77 
78  if (!TextTools::isEmpty(desc.substr(end + 1)))
79  throw KeyvalException("Bad keyval procedure, extra characters after closing parenthesis: " + desc.substr(end + 1));
80  // Get the procedure name (without leading spaces):
81 
82  string newDesc = TextTools::removeFirstWhiteSpaces(desc.substr(0, begin)) + "(";
83 
84  string desckv = desc.substr(begin + 1, end - begin - 1);
85 
86  unique_ptr<StringTokenizer> st;
87  if (nested)
88  st.reset(new NestedStringTokenizer(desckv, "(", ")", split));
89  else
90  st.reset(new StringTokenizer(desckv, split));
91  string key, val;
92  vector<string> tokens;
93  // Check tokens:
94  string token;
95 
96  while (st->hasMoreToken())
97  {
98  token = st->nextToken();
99  if (token == "=")
100  {
101  // We need to merge the next token with the last one:
102  if (tokens.size() == 0)
103  throw KeyvalException("Invalid syntax, found '=' without argument name.");
104  if (!st->hasMoreToken())
105  throw KeyvalException("Invalid syntax, found '=' without argument value.");
106  string nextToken = st->nextToken();
107  if (nextToken == "=")
108  throw KeyvalException("Invalid syntax, found a double '='.");
109  tokens[tokens.size() - 1] += "=" + nextToken;
110  }
111  else
112  {
113  tokens.push_back(token);
114  }
115  }
116 
117  for (vector<string>::iterator it = tokens.begin(); it != tokens.end(); it++)
118  {
119  singleKeyval(*it, key, val);
121  if (it != tokens.begin())
122  newDesc += split;
123 
124  map<string, string>::const_iterator iter = newkeyvals.find(key);
125 
126  if (iter != newkeyvals.end())
127  newDesc += key + "=" + iter->second;
128  else
129  newDesc += *it;
130  }
131 
132  newDesc += ")";
133 
134  return newDesc;
135 }
136 
137 void KeyvalTools::parseProcedure(const std::string& desc, std::string& name, std::map<std::string, std::string>& args)
138 {
139  string::size_type begin = desc.find_first_of("(");
140  string::size_type end = desc.find_last_of(")");
141 
142  if (begin == string::npos && end == string::npos)
143  {
144  // Empty procedure:
145  name = desc;
146  return;
147  }
148  if (begin == string::npos && end != string::npos)
149  throw KeyvalException("Bad keyval procedure, missing opening parenthesis.");
150  if (begin == string::npos && end != string::npos)
151  throw KeyvalException("Bad keyval procedure, missing closing parenthesis.");
152 
153  if (!TextTools::isEmpty(desc.substr(end + 1)))
154  throw KeyvalException("Bad keyval procedure, extra characters after closing parenthesis: " + desc.substr(end + 1));
155  // Get the procedure name (without leading spaces):
156  name = TextTools::removeFirstWhiteSpaces(desc.substr(0, begin));
157  multipleKeyvals(desc.substr(begin + 1, end - begin - 1), args);
158 }
A tokenizer for strings.
const std::string & nextToken()
Get the next available token. If no token is availbale, throw an Exception.
bool hasMoreToken() const
Tell if some tokens are still available.
STL namespace.
std::string removeSurroundingWhiteSpaces(const std::string &s)
Remove all white spaces characters at the beginning and the end of a string.
Definition: TextTools.cpp:90
static std::string changeKeyvals(const std::string &desc, const std::map< std::string, std::string > &newkeyvals, const std::string &split=",", bool nested=true)
Change several keys to new corresponding values (General purpose function).
Definition: KeyvalTools.cpp:63
static void singleKeyval(const std::string &desc, std::string &key, std::string &val, const std::string &split="=")
Split a string into a key and a value (General purpose function).
Definition: KeyvalTools.cpp:14
std::string removeFirstWhiteSpaces(const std::string &s)
Remove all white spaces characters at the beginning of a string.
Definition: TextTools.cpp:69
Exception thrown by the Keyval parser.
Definition: KeyvalTools.h:21
static void parseProcedure(const std::string &desc, std::string &name, std::map< std::string, std::string > &args)
Parse (not recursively) a procedure string.
An improved tokenizer for strings.
static void multipleKeyvals(const std::string &desc, std::map< std::string, std::string > &keyvals, const std::string &split=",", bool nested=true)
Split a string into several keys and corresponding values (General purpose function).
Definition: KeyvalTools.cpp:23
bool isEmpty(const std::string &s)
Tell if a string is empty. A string is considered to be &#39;empty&#39; if it is only made of white spaces...
Definition: TextTools.cpp:20
std::vector< std::string > split(const std::string &s, std::size_t n)
Definition: TextTools.cpp:263