blob: 2f51c9e358b3922d5a2e28d899085b1ce8f33e1c [file] [log] [blame]
Steven Morelandaf440142016-09-07 10:09:11 -07001/*
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
Steven Moreland868aff82016-09-12 16:20:56 +000019#include <sstream>
Yifan Hong42009032016-09-29 09:38:15 -070020#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]*"
28static const std::regex kStartUppercase("^" UPPERCASE);
29static const std::regex kStartLowercase("^" LOWERCASE);
30static const std::regex kStartCapcase("^" CAPCASE);
Steven Moreland868aff82016-09-12 16:20:56 +000031
Steven Morelandaf440142016-09-07 10:09:11 -070032namespace android {
33
34// static
Yifan Hong42009032016-09-29 09:38:15 -070035std::string StringHelper::Uppercase(const std::string &in) {
Steven Morelandaf440142016-09-07 10:09:11 -070036 std::string out{in};
37
38 for (auto &ch : out) {
39 ch = toupper(ch);
40 }
41
42 return out;
43}
44
45// static
Yifan Hong42009032016-09-29 09:38:15 -070046std::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
Steven Moreland868aff82016-09-12 16:20:56 +000057std::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
Yifan Hong42009032016-09-29 09:38:15 -070068void StringHelper::Tokenize(const std::string &in,
69 std::vector<std::string> *vec) {
Steven Moreland868aff82016-09-12 16:20:56 +000070
Yifan Hong42009032016-09-29 09:38:15 -070071 std::smatch match;
72 if (in.empty()) {
73 vec->clear();
74 return;
Steven Moreland95b46232016-09-20 14:46:55 -070075 }
Yifan Hong42009032016-09-29 09:38:15 -070076 std::string copy(in);
77 vec->clear();
78 std::vector<std::string> matches;
Steven Moreland95b46232016-09-20 14:46:55 -070079
Yifan Hong42009032016-09-29 09:38:15 -070080 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 }
Steven Moreland95b46232016-09-20 14:46:55 -0700103}
104
105// static
Yifan Hong42009032016-09-29 09:38:15 -0700106std::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;
Steven Moreland868aff82016-09-12 16:20:56 +0000113 }
Yifan Hong42009032016-09-29 09:38:15 -0700114 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}
Steven Moreland868aff82016-09-12 16:20:56 +0000120
Yifan Hong42009032016-09-29 09:38:15 -0700121// static
122std::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
132std::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
142std::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
152std::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;
Steven Moreland868aff82016-09-12 16:20:56 +0000167}
168
169// static
Steven Morelandf9a6ef32016-09-27 14:20:56 -0700170bool 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
Steven Moreland95b46232016-09-20 14:46:55 -0700176bool 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
Steven Morelandf9a6ef32016-09-27 14:20:56 -0700182std::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());
Steven Moreland95b46232016-09-20 14:46:55 -0700185 }
186
187 return in;
188}
189
190// static
Steven Morelandf9a6ef32016-09-27 14:20:56 -0700191std::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
Yifan Hong42009032016-09-29 09:38:15 -0700199// static
200std::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
210std::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}
Steven Morelandf9a6ef32016-09-27 14:20:56 -0700218
219// static
Steven Morelandaf440142016-09-07 10:09:11 -0700220void 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
Yifan Hongdb364982016-11-18 14:40:59 -0800231 if (startPos <= s.length()) {
Steven Morelandaf440142016-09-07 10:09:11 -0700232 components->push_back(s.substr(startPos));
233 }
234}
235
236// static
237std::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