blob: 3718d53535b43f30f8c3212a5b2614c03eb77753 [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
Yifan Hong42009032016-09-29 09:38:15 -070034std::string StringHelper::Uppercase(const std::string &in) {
Steven Morelandaf440142016-09-07 10:09:11 -070035 std::string out{in};
36
37 for (auto &ch : out) {
38 ch = toupper(ch);
39 }
40
41 return out;
42}
43
Yifan Hong42009032016-09-29 09:38:15 -070044std::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
Steven Moreland868aff82016-09-12 16:20:56 +000054std::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
Yifan Hong42009032016-09-29 09:38:15 -070064void StringHelper::Tokenize(const std::string &in,
65 std::vector<std::string> *vec) {
Steven Moreland868aff82016-09-12 16:20:56 +000066
Yifan Hong42009032016-09-29 09:38:15 -070067 std::smatch match;
68 if (in.empty()) {
69 vec->clear();
70 return;
Steven Moreland95b46232016-09-20 14:46:55 -070071 }
Yifan Hong42009032016-09-29 09:38:15 -070072 std::string copy(in);
73 vec->clear();
74 std::vector<std::string> matches;
Steven Moreland95b46232016-09-20 14:46:55 -070075
Yifan Hong42009032016-09-29 09:38:15 -070076 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 }
Steven Moreland95b46232016-09-20 14:46:55 -070099}
100
Yifan Hong42009032016-09-29 09:38:15 -0700101std::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;
Steven Moreland868aff82016-09-12 16:20:56 +0000108 }
Yifan Hong42009032016-09-29 09:38:15 -0700109 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}
Steven Moreland868aff82016-09-12 16:20:56 +0000115
Yifan Hong42009032016-09-29 09:38:15 -0700116std::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
Yifan Hong42009032016-09-29 09:38:15 -0700125std::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
Yifan Hong42009032016-09-29 09:38:15 -0700134std::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
Yifan Hong42009032016-09-29 09:38:15 -0700143std::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;
Steven Moreland868aff82016-09-12 16:20:56 +0000158}
159
Steven Morelandf9a6ef32016-09-27 14:20:56 -0700160bool 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
Steven Moreland95b46232016-09-20 14:46:55 -0700165bool 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
Steven Morelandf9a6ef32016-09-27 14:20:56 -0700170std::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());
Steven Moreland95b46232016-09-20 14:46:55 -0700173 }
174
175 return in;
176}
177
Steven Morelandf9a6ef32016-09-27 14:20:56 -0700178std::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
Yifan Hong42009032016-09-29 09:38:15 -0700186std::string StringHelper::RTrimAll(const std::string &in, const std::string &suffix) {
187 std::string copy(in);
188 while (EndsWith(copy, suffix)) {
189 copy = copy.substr(0, copy.size() - suffix.size());
190 }
191
192 return copy;
193}
194
Yifan Hong42009032016-09-29 09:38:15 -0700195std::string StringHelper::LTrimAll(const std::string &in, const std::string &prefix) {
196 std::string copy(in);
197 while (StartsWith(copy, prefix)) {
198 copy = copy.substr(prefix.size());
199 }
200
201 return copy;
202}
Steven Morelandf9a6ef32016-09-27 14:20:56 -0700203
Steven Morelandaf440142016-09-07 10:09:11 -0700204void StringHelper::SplitString(
205 const std::string &s, char c, std::vector<std::string> *components) {
206 components->clear();
207
208 size_t startPos = 0;
209 size_t matchPos;
210 while ((matchPos = s.find(c, startPos)) != std::string::npos) {
211 components->push_back(s.substr(startPos, matchPos - startPos));
212 startPos = matchPos + 1;
213 }
214
Yifan Hongdb364982016-11-18 14:40:59 -0800215 if (startPos <= s.length()) {
Steven Morelandaf440142016-09-07 10:09:11 -0700216 components->push_back(s.substr(startPos));
217 }
218}
219
Steven Morelandaf440142016-09-07 10:09:11 -0700220std::string StringHelper::JoinStrings(
221 const std::vector<std::string> &components,
222 const std::string &separator) {
223 std::string out;
224 bool first = true;
225 for (const auto &component : components) {
226 if (!first) {
227 out += separator;
228 }
229 out += component;
230
231 first = false;
232 }
233
234 return out;
235}
236
237} // namespace android
238