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 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