|
||||
File indexing completed on 2024-11-15 09:01:16
0001 // 0002 // Copyright 2017 The Abseil Authors. 0003 // 0004 // Licensed under the Apache License, Version 2.0 (the "License"); 0005 // you may not use this file except in compliance with the License. 0006 // You may obtain a copy of the License at 0007 // 0008 // https://www.apache.org/licenses/LICENSE-2.0 0009 // 0010 // Unless required by applicable law or agreed to in writing, software 0011 // distributed under the License is distributed on an "AS IS" BASIS, 0012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0013 // See the License for the specific language governing permissions and 0014 // limitations under the License. 0015 // 0016 // ----------------------------------------------------------------------------- 0017 // File: str_replace.h 0018 // ----------------------------------------------------------------------------- 0019 // 0020 // This file defines `absl::StrReplaceAll()`, a general-purpose string 0021 // replacement function designed for large, arbitrary text substitutions, 0022 // especially on strings which you are receiving from some other system for 0023 // further processing (e.g. processing regular expressions, escaping HTML 0024 // entities, etc.). `StrReplaceAll` is designed to be efficient even when only 0025 // one substitution is being performed, or when substitution is rare. 0026 // 0027 // If the string being modified is known at compile-time, and the substitutions 0028 // vary, `absl::Substitute()` may be a better choice. 0029 // 0030 // Example: 0031 // 0032 // std::string html_escaped = absl::StrReplaceAll(user_input, { 0033 // {"&", "&"}, 0034 // {"<", "<"}, 0035 // {">", ">"}, 0036 // {"\"", """}, 0037 // {"'", "'"}}); 0038 #ifndef ABSL_STRINGS_STR_REPLACE_H_ 0039 #define ABSL_STRINGS_STR_REPLACE_H_ 0040 0041 #include <string> 0042 #include <utility> 0043 #include <vector> 0044 0045 #include "absl/base/attributes.h" 0046 #include "absl/base/nullability.h" 0047 #include "absl/strings/string_view.h" 0048 0049 namespace absl { 0050 ABSL_NAMESPACE_BEGIN 0051 0052 // StrReplaceAll() 0053 // 0054 // Replaces character sequences within a given string with replacements provided 0055 // within an initializer list of key/value pairs. Candidate replacements are 0056 // considered in order as they occur within the string, with earlier matches 0057 // taking precedence, and longer matches taking precedence for candidates 0058 // starting at the same position in the string. Once a substitution is made, the 0059 // replaced text is not considered for any further substitutions. 0060 // 0061 // Example: 0062 // 0063 // std::string s = absl::StrReplaceAll( 0064 // "$who bought $count #Noun. Thanks $who!", 0065 // {{"$count", absl::StrCat(5)}, 0066 // {"$who", "Bob"}, 0067 // {"#Noun", "Apples"}}); 0068 // EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); 0069 ABSL_MUST_USE_RESULT std::string StrReplaceAll( 0070 absl::string_view s, 0071 std::initializer_list<std::pair<absl::string_view, absl::string_view>> 0072 replacements); 0073 0074 // Overload of `StrReplaceAll()` to accept a container of key/value replacement 0075 // pairs (typically either an associative map or a `std::vector` of `std::pair` 0076 // elements). A vector of pairs is generally more efficient. 0077 // 0078 // Examples: 0079 // 0080 // std::map<const absl::string_view, const absl::string_view> replacements; 0081 // replacements["$who"] = "Bob"; 0082 // replacements["$count"] = "5"; 0083 // replacements["#Noun"] = "Apples"; 0084 // std::string s = absl::StrReplaceAll( 0085 // "$who bought $count #Noun. Thanks $who!", 0086 // replacements); 0087 // EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); 0088 // 0089 // // A std::vector of std::pair elements can be more efficient. 0090 // std::vector<std::pair<const absl::string_view, std::string>> replacements; 0091 // replacements.push_back({"&", "&"}); 0092 // replacements.push_back({"<", "<"}); 0093 // replacements.push_back({">", ">"}); 0094 // std::string s = absl::StrReplaceAll("if (ptr < &foo)", 0095 // replacements); 0096 // EXPECT_EQ("if (ptr < &foo)", s); 0097 template <typename StrToStrMapping> 0098 std::string StrReplaceAll(absl::string_view s, 0099 const StrToStrMapping& replacements); 0100 0101 // Overload of `StrReplaceAll()` to replace character sequences within a given 0102 // output string *in place* with replacements provided within an initializer 0103 // list of key/value pairs, returning the number of substitutions that occurred. 0104 // 0105 // Example: 0106 // 0107 // std::string s = std::string("$who bought $count #Noun. Thanks $who!"); 0108 // int count; 0109 // count = absl::StrReplaceAll({{"$count", absl::StrCat(5)}, 0110 // {"$who", "Bob"}, 0111 // {"#Noun", "Apples"}}, &s); 0112 // EXPECT_EQ(count, 4); 0113 // EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); 0114 int StrReplaceAll( 0115 std::initializer_list<std::pair<absl::string_view, absl::string_view>> 0116 replacements, 0117 absl::Nonnull<std::string*> target); 0118 0119 // Overload of `StrReplaceAll()` to replace patterns within a given output 0120 // string *in place* with replacements provided within a container of key/value 0121 // pairs. 0122 // 0123 // Example: 0124 // 0125 // std::string s = std::string("if (ptr < &foo)"); 0126 // int count = absl::StrReplaceAll({{"&", "&"}, 0127 // {"<", "<"}, 0128 // {">", ">"}}, &s); 0129 // EXPECT_EQ(count, 2); 0130 // EXPECT_EQ("if (ptr < &foo)", s); 0131 template <typename StrToStrMapping> 0132 int StrReplaceAll(const StrToStrMapping& replacements, 0133 absl::Nonnull<std::string*> target); 0134 0135 // Implementation details only, past this point. 0136 namespace strings_internal { 0137 0138 struct ViableSubstitution { 0139 absl::string_view old; 0140 absl::string_view replacement; 0141 size_t offset; 0142 0143 ViableSubstitution(absl::string_view old_str, 0144 absl::string_view replacement_str, size_t offset_val) 0145 : old(old_str), replacement(replacement_str), offset(offset_val) {} 0146 0147 // One substitution occurs "before" another (takes priority) if either 0148 // it has the lowest offset, or it has the same offset but a larger size. 0149 bool OccursBefore(const ViableSubstitution& y) const { 0150 if (offset != y.offset) return offset < y.offset; 0151 return old.size() > y.old.size(); 0152 } 0153 }; 0154 0155 // Build a vector of ViableSubstitutions based on the given list of 0156 // replacements. subs can be implemented as a priority_queue. However, it turns 0157 // out that most callers have small enough a list of substitutions that the 0158 // overhead of such a queue isn't worth it. 0159 template <typename StrToStrMapping> 0160 std::vector<ViableSubstitution> FindSubstitutions( 0161 absl::string_view s, const StrToStrMapping& replacements) { 0162 std::vector<ViableSubstitution> subs; 0163 subs.reserve(replacements.size()); 0164 0165 for (const auto& rep : replacements) { 0166 using std::get; 0167 absl::string_view old(get<0>(rep)); 0168 0169 size_t pos = s.find(old); 0170 if (pos == s.npos) continue; 0171 0172 // Ignore attempts to replace "". This condition is almost never true, 0173 // but above condition is frequently true. That's why we test for this 0174 // now and not before. 0175 if (old.empty()) continue; 0176 0177 subs.emplace_back(old, get<1>(rep), pos); 0178 0179 // Insertion sort to ensure the last ViableSubstitution comes before 0180 // all the others. 0181 size_t index = subs.size(); 0182 while (--index && subs[index - 1].OccursBefore(subs[index])) { 0183 std::swap(subs[index], subs[index - 1]); 0184 } 0185 } 0186 return subs; 0187 } 0188 0189 int ApplySubstitutions(absl::string_view s, 0190 absl::Nonnull<std::vector<ViableSubstitution>*> subs_ptr, 0191 absl::Nonnull<std::string*> result_ptr); 0192 0193 } // namespace strings_internal 0194 0195 template <typename StrToStrMapping> 0196 std::string StrReplaceAll(absl::string_view s, 0197 const StrToStrMapping& replacements) { 0198 auto subs = strings_internal::FindSubstitutions(s, replacements); 0199 std::string result; 0200 result.reserve(s.size()); 0201 strings_internal::ApplySubstitutions(s, &subs, &result); 0202 return result; 0203 } 0204 0205 template <typename StrToStrMapping> 0206 int StrReplaceAll(const StrToStrMapping& replacements, 0207 absl::Nonnull<std::string*> target) { 0208 auto subs = strings_internal::FindSubstitutions(*target, replacements); 0209 if (subs.empty()) return 0; 0210 0211 std::string result; 0212 result.reserve(target->size()); 0213 int substitutions = 0214 strings_internal::ApplySubstitutions(*target, &subs, &result); 0215 target->swap(result); 0216 return substitutions; 0217 } 0218 0219 ABSL_NAMESPACE_END 0220 } // namespace absl 0221 0222 #endif // ABSL_STRINGS_STR_REPLACE_H_
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |