• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Uppercase(const std::string & in)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 
Lowercase(const std::string & in)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 
Capitalize(const std::string & in)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 
Tokenize(const std::string & in,std::vector<std::string> * vec)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 
ToCamelCase(const std::string & in)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 
ToPascalCase(const std::string & in)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 
ToUpperSnakeCase(const std::string & in)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 
ToLowerSnakeCase(const std::string & in)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 
ToCase(StringHelper::Case c,const std::string & in)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 
EndsWith(const std::string & in,const std::string & suffix)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 
StartsWith(const std::string & in,const std::string & prefix)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 
RTrim(const std::string & in,const std::string & suffix)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 
LTrim(const std::string & in,const std::string & prefix)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 
RTrimAll(const std::string & in,const std::string & suffix)186 std::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 
LTrimAll(const std::string & in,const std::string & prefix)195 std::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 }
203 
SplitString(const std::string & s,char c,std::vector<std::string> * components)204 void 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 
215     if (startPos <= s.length()) {
216         components->push_back(s.substr(startPos));
217     }
218 }
219 
JoinStrings(const std::vector<std::string> & components,const std::string & separator)220 std::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 
239