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 std::string StringHelper::Uppercase(const std::string &in) { 35 std::string out{in}; 36 37 for (auto &ch : out) { 38 ch = toupper(ch); 39 } 40 41 return out; 42 } 43 44 std::string StringHelper::Lowercase(const std::string &in) { 45 std::string out{in}; 46 47 for (auto &ch : out) { 48 ch = tolower(ch); 49 } 50 51 return out; 52 } 53 54 std::string StringHelper::Capitalize(const std::string &in) { 55 std::string out{in}; 56 57 if(!out.empty()) { 58 out[0] = toupper(out[0]); 59 } 60 61 return out; 62 } 63 64 void StringHelper::Tokenize(const std::string &in, 65 std::vector<std::string> *vec) { 66 67 std::smatch match; 68 if (in.empty()) { 69 vec->clear(); 70 return; 71 } 72 std::string copy(in); 73 vec->clear(); 74 std::vector<std::string> matches; 75 76 copy = RTrimAll(copy, "_"); 77 while(!copy.empty()) { 78 copy = LTrimAll(copy, "_"); 79 if (std::regex_search(copy, match, kStartLowercase)) 80 matches.push_back(match.str(0)); 81 if (std::regex_search(copy, match, kStartCapcase)) 82 matches.push_back(match.str(0)); 83 if (std::regex_search(copy, match, kStartUppercase)) 84 matches.push_back(match.str(0)); 85 if (!matches.empty()) { 86 std::string &maxmatch = matches[0]; 87 for (std::string &match : matches) 88 if(match.length() > maxmatch.length()) 89 maxmatch = match; 90 vec->push_back(maxmatch); 91 copy = copy.substr(maxmatch.length()); 92 matches.clear(); 93 continue; 94 } 95 LOG(WARNING) << "Could not stylize \"" << in << "\""; 96 // don't know what to do, so push back the rest of the string. 97 vec->push_back(copy); 98 } 99 } 100 101 std::string StringHelper::ToCamelCase(const std::string &in) { 102 std::vector<std::string> components; 103 Tokenize(in, &components); 104 if (components.empty()) { 105 if (!in.empty()) 106 LOG(WARNING) << "Could not stylize \"" << in << "\""; 107 return in; 108 } 109 components[0] = Lowercase(components[0]); 110 for (size_t i = 1; i < components.size(); i++) { 111 components[i] = Capitalize(components[i]); 112 } 113 return JoinStrings(components, ""); 114 } 115 116 std::string StringHelper::ToPascalCase(const std::string &in) { 117 std::vector<std::string> components; 118 Tokenize(in, &components); 119 for (size_t i = 0; i < components.size(); i++) { 120 components[i] = Capitalize(components[i]); 121 } 122 return JoinStrings(components, ""); 123 } 124 125 std::string StringHelper::ToUpperSnakeCase(const std::string &in) { 126 std::vector<std::string> components; 127 Tokenize(in, &components); 128 for (size_t i = 0; i < components.size(); i++) { 129 components[i] = Uppercase(components[i]); 130 } 131 return JoinStrings(components, "_"); 132 } 133 134 std::string StringHelper::ToLowerSnakeCase(const std::string &in) { 135 std::vector<std::string> components; 136 Tokenize(in, &components); 137 for (size_t i = 0; i < components.size(); i++) { 138 components[i] = Lowercase(components[i]); 139 } 140 return JoinStrings(components, "_"); 141 } 142 143 std::string StringHelper::ToCase(StringHelper::Case c, const std::string &in) { 144 switch(c) { 145 case kCamelCase: 146 return ToCamelCase(in); 147 case kPascalCase: 148 return ToPascalCase(in); 149 case kUpperSnakeCase: 150 return ToUpperSnakeCase(in); 151 case kLowerSnakeCase: 152 return ToLowerSnakeCase(in); 153 case kNoCase: 154 return in; 155 } 156 LOG(FATAL) << "Should not reach here."; 157 return in; 158 } 159 160 bool StringHelper::EndsWith(const std::string &in, const std::string &suffix) { 161 return in.size() >= suffix.size() && 162 in.substr(in.size() - suffix.size()) == suffix; 163 } 164 165 bool StringHelper::StartsWith(const std::string &in, const std::string &prefix) { 166 return in.size() >= prefix.size() && 167 in.substr(0, prefix.size()) == prefix; 168 } 169 170 std::string StringHelper::RTrim(const std::string &in, const std::string &suffix) { 171 if (EndsWith(in, suffix)) { 172 return in.substr(0, in.size() - suffix.size()); 173 } 174 175 return in; 176 } 177 178 std::string StringHelper::LTrim(const std::string &in, const std::string &prefix) { 179 if (StartsWith(in, prefix)) { 180 return in.substr(prefix.size()); 181 } 182 183 return in; 184 } 185 186 std::string StringHelper::RTrimAll(const std::string &in, const std::string &suffix) { 187 if (suffix.empty()) { 188 return in; 189 } 190 191 std::string copy(in); 192 while (EndsWith(copy, suffix)) { 193 copy = copy.substr(0, copy.size() - suffix.size()); 194 } 195 196 return copy; 197 } 198 199 std::string StringHelper::LTrimAll(const std::string &in, const std::string &prefix) { 200 if (prefix.empty()) { 201 return in; 202 } 203 204 std::string copy(in); 205 while (StartsWith(copy, prefix)) { 206 copy = copy.substr(prefix.size()); 207 } 208 209 return copy; 210 } 211 212 void StringHelper::SplitString( 213 const std::string &s, char c, std::vector<std::string> *components) { 214 components->clear(); 215 216 size_t startPos = 0; 217 size_t matchPos; 218 while ((matchPos = s.find(c, startPos)) != std::string::npos) { 219 components->push_back(s.substr(startPos, matchPos - startPos)); 220 startPos = matchPos + 1; 221 } 222 223 if (startPos <= s.length()) { 224 components->push_back(s.substr(startPos)); 225 } 226 } 227 228 std::string StringHelper::JoinStrings( 229 const std::vector<std::string> &components, 230 const std::string &separator) { 231 std::string out; 232 bool first = true; 233 for (const auto &component : components) { 234 if (!first) { 235 out += separator; 236 } 237 out += component; 238 239 first = false; 240 } 241 242 return out; 243 } 244 245 } // namespace android 246 247