Home | History | Annotate | Download | only in utils
      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