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
Substitute(const StringPiece format,const std::vector<StringPiece> & args,std::string * output)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
Substitute(const StringPiece format,const std::vector<StringPiece> & args)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