1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "StringHelper.h" 18 19 #include <sstream> 20 #include <regex> 21 22 #include <android-base/macros.h> 23 #include <android-base/logging.h> 24 25 #define UPPERCASE "[A-Z0-9]+" 26 #define LOWERCASE "[a-z0-9]+" 27 #define CAPCASE "[A-Z0-9][a-z0-9]*" 28 static const std::regex kStartUppercase("^" UPPERCASE); 29 static const std::regex kStartLowercase("^" LOWERCASE); 30 static const std::regex kStartCapcase("^" CAPCASE); 31 32 namespace android { 33 34 // static 35 std::string StringHelper::Uppercase(const std::string &in) { 36 std::string out{in}; 37 38 for (auto &ch : out) { 39 ch = toupper(ch); 40 } 41 42 return out; 43 } 44 45 // static 46 std::string StringHelper::Lowercase(const std::string &in) { 47 std::string out{in}; 48 49 for (auto &ch : out) { 50 ch = tolower(ch); 51 } 52 53 return out; 54 } 55 56 // static 57 std::string StringHelper::Capitalize(const std::string &in) { 58 std::string out{in}; 59 60 if(!out.empty()) { 61 out[0] = toupper(out[0]); 62 } 63 64 return out; 65 } 66 67 // static 68 void StringHelper::Tokenize(const std::string &in, 69 std::vector<std::string> *vec) { 70 71 std::smatch match; 72 if (in.empty()) { 73 vec->clear(); 74 return; 75 } 76 std::string copy(in); 77 vec->clear(); 78 std::vector<std::string> matches; 79 80 copy = RTrimAll(copy, "_"); 81 while(!copy.empty()) { 82 copy = LTrimAll(copy, "_"); 83 if (std::regex_search(copy, match, kStartLowercase)) 84 matches.push_back(match.str(0)); 85 if (std::regex_search(copy, match, kStartCapcase)) 86 matches.push_back(match.str(0)); 87 if (std::regex_search(copy, match, kStartUppercase)) 88 matches.push_back(match.str(0)); 89 if (!matches.empty()) { 90 std::string &maxmatch = matches[0]; 91 for (std::string &match : matches) 92 if(match.length() > maxmatch.length()) 93 maxmatch = match; 94 vec->push_back(maxmatch); 95 copy = copy.substr(maxmatch.length()); 96 matches.clear(); 97 continue; 98 } 99 LOG(WARNING) << "Could not stylize \"" << in << "\""; 100 // don't know what to do, so push back the rest of the string. 101 vec->push_back(copy); 102 } 103 } 104 105 // static 106 std::string StringHelper::ToCamelCase(const std::string &in) { 107 std::vector<std::string> components; 108 Tokenize(in, &components); 109 if (components.empty()) { 110 if (!in.empty()) 111 LOG(WARNING) << "Could not stylize \"" << in << "\""; 112 return in; 113 } 114 components[0] = Lowercase(components[0]); 115 for (size_t i = 1; i < components.size(); i++) { 116 components[i] = Capitalize(components[i]); 117 } 118 return JoinStrings(components, ""); 119 } 120 121 // static 122 std::string StringHelper::ToPascalCase(const std::string &in) { 123 std::vector<std::string> components; 124 Tokenize(in, &components); 125 for (size_t i = 0; i < components.size(); i++) { 126 components[i] = Capitalize(components[i]); 127 } 128 return JoinStrings(components, ""); 129 } 130 131 // static 132 std::string StringHelper::ToUpperSnakeCase(const std::string &in) { 133 std::vector<std::string> components; 134 Tokenize(in, &components); 135 for (size_t i = 0; i < components.size(); i++) { 136 components[i] = Uppercase(components[i]); 137 } 138 return JoinStrings(components, "_"); 139 } 140 141 // static 142 std::string StringHelper::ToLowerSnakeCase(const std::string &in) { 143 std::vector<std::string> components; 144 Tokenize(in, &components); 145 for (size_t i = 0; i < components.size(); i++) { 146 components[i] = Lowercase(components[i]); 147 } 148 return JoinStrings(components, "_"); 149 } 150 151 // static 152 std::string StringHelper::ToCase(StringHelper::Case c, const std::string &in) { 153 switch(c) { 154 case kCamelCase: 155 return ToCamelCase(in); 156 case kPascalCase: 157 return ToPascalCase(in); 158 case kUpperSnakeCase: 159 return ToUpperSnakeCase(in); 160 case kLowerSnakeCase: 161 return ToLowerSnakeCase(in); 162 case kNoCase: 163 return in; 164 } 165 LOG(FATAL) << "Should not reach here."; 166 return in; 167 } 168 169 // static 170 bool StringHelper::EndsWith(const std::string &in, const std::string &suffix) { 171 return in.size() >= suffix.size() && 172 in.substr(in.size() - suffix.size()) == suffix; 173 } 174 175 // static 176 bool StringHelper::StartsWith(const std::string &in, const std::string &prefix) { 177 return in.size() >= prefix.size() && 178 in.substr(0, prefix.size()) == prefix; 179 } 180 181 // static 182 std::string StringHelper::RTrim(const std::string &in, const std::string &suffix) { 183 if (EndsWith(in, suffix)) { 184 return in.substr(0, in.size() - suffix.size()); 185 } 186 187 return in; 188 } 189 190 // static 191 std::string StringHelper::LTrim(const std::string &in, const std::string &prefix) { 192 if (StartsWith(in, prefix)) { 193 return in.substr(prefix.size()); 194 } 195 196 return in; 197 } 198 199 // static 200 std::string StringHelper::RTrimAll(const std::string &in, const std::string &suffix) { 201 std::string copy(in); 202 while (EndsWith(copy, suffix)) { 203 copy = copy.substr(0, copy.size() - suffix.size()); 204 } 205 206 return copy; 207 } 208 209 // static 210 std::string StringHelper::LTrimAll(const std::string &in, const std::string &prefix) { 211 std::string copy(in); 212 while (StartsWith(copy, prefix)) { 213 copy = copy.substr(prefix.size()); 214 } 215 216 return copy; 217 } 218 219 // static 220 void StringHelper::SplitString( 221 const std::string &s, char c, std::vector<std::string> *components) { 222 components->clear(); 223 224 size_t startPos = 0; 225 size_t matchPos; 226 while ((matchPos = s.find(c, startPos)) != std::string::npos) { 227 components->push_back(s.substr(startPos, matchPos - startPos)); 228 startPos = matchPos + 1; 229 } 230 231 if (startPos <= s.length()) { 232 components->push_back(s.substr(startPos)); 233 } 234 } 235 236 // static 237 std::string StringHelper::JoinStrings( 238 const std::vector<std::string> &components, 239 const std::string &separator) { 240 std::string out; 241 bool first = true; 242 for (const auto &component : components) { 243 if (!first) { 244 out += separator; 245 } 246 out += component; 247 248 first = false; 249 } 250 251 return out; 252 } 253 254 } // namespace android 255 256