Home | History | Annotate | Download | only in strings
      1 /*
      2  * Copyright (C) 2018 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 "utils/strings/substitute.h"
     18 
     19 #include <algorithm>
     20 
     21 #include "utils/base/logging.h"
     22 
     23 namespace libtextclassifier3 {
     24 namespace strings {
     25 
     26 bool Substitute(const StringPiece format, const std::vector<StringPiece>& args,
     27                 std::string* output) {
     28   // Determine total size needed.
     29   size_t size = 0;
     30   for (size_t i = 0; i < format.size(); i++) {
     31     if (format[i] == '$') {
     32       if (i + 1 >= format.size()) {
     33         TC3_LOG(ERROR) << "Invalid format string: " << format.ToString();
     34         return false;
     35       } else if (isdigit(format[i + 1])) {
     36         int index = format[i + 1] - '0';
     37         if (static_cast<size_t>(index) >= args.size()) {
     38           TC3_LOG(ERROR) << "Asked for " << index << ", but only "
     39                          << args.size() << " arguments given";
     40           return false;
     41         }
     42         size += args[index].size();
     43         ++i;  // Skip next char.
     44       } else if (format[i + 1] == '$') {
     45         ++size;
     46         ++i;  // Skip next char.
     47       } else {
     48         TC3_LOG(ERROR) << "Invalid format string: " << format.ToString();
     49         return false;
     50       }
     51     } else {
     52       ++size;
     53     }
     54   }
     55 
     56   if (size == 0) {
     57     output->clear();
     58     return true;
     59   }
     60 
     61   // Build the string.
     62   output->resize(size);
     63   char* target = &(*output)[0];
     64   for (size_t i = 0; i < format.size(); i++) {
     65     if (format[i] == '$') {
     66       if (isdigit(format[i + 1])) {
     67         const StringPiece src = args[format[i + 1] - '0'];
     68         target = std::copy(src.data(), src.data() + src.size(), target);
     69         ++i;  // Skip next char.
     70       } else if (format[i + 1] == '$') {
     71         *target++ = '$';
     72         ++i;  // Skip next char.
     73       }
     74     } else {
     75       *target++ = format[i];
     76     }
     77   }
     78   return true;
     79 }
     80 
     81 std::string Substitute(const StringPiece format,
     82                        const std::vector<StringPiece>& args) {
     83   std::string result;
     84   if (!Substitute(format, args, &result)) {
     85     return "";
     86   }
     87   return result;
     88 }
     89 
     90 }  // namespace strings
     91 }  // namespace libtextclassifier3
     92