| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- #include "jinja/string.h"
- #include "jinja/value.h"
- #include <algorithm>
- #include <functional>
- #include <optional>
- #include <sstream>
- #include <string>
- #include <vector>
- namespace jinja {
- //
- // string_part
- //
- bool string_part::is_uppercase() const {
- for (char c : val) {
- if (std::islower(static_cast<unsigned char>(c))) {
- return false;
- }
- }
- return true;
- }
- bool string_part::is_lowercase() const {
- for (char c : val) {
- if (std::isupper(static_cast<unsigned char>(c))) {
- return false;
- }
- }
- return true;
- }
- //
- // string
- //
- void string::mark_input() {
- for (auto & part : parts) {
- part.is_input = true;
- }
- }
- std::string string::str() const {
- if (parts.size() == 1) {
- return parts[0].val;
- }
- std::ostringstream oss;
- for (const auto & part : parts) {
- oss << part.val;
- }
- return oss.str();
- }
- size_t string::length() const {
- size_t len = 0;
- for (const auto & part : parts) {
- len += part.val.length();
- }
- return len;
- }
- bool string::all_parts_are_input() const {
- for (const auto & part : parts) {
- if (!part.is_input) {
- return false;
- }
- }
- return true;
- }
- bool string::is_uppercase() const {
- for (const auto & part : parts) {
- if (!part.is_uppercase()) {
- return false;
- }
- }
- return true;
- }
- bool string::is_lowercase() const {
- for (const auto & part : parts) {
- if (!part.is_lowercase()) {
- return false;
- }
- }
- return true;
- }
- // mark this string as input if other has ALL parts as input
- void string::mark_input_based_on(const string & other) {
- if (other.all_parts_are_input()) {
- for (auto & part : parts) {
- part.is_input = true;
- }
- }
- }
- string string::append(const string & other) {
- for (const auto & part : other.parts) {
- parts.push_back(part);
- }
- return *this;
- }
- // in-place transformation
- using transform_fn = std::function<std::string(const std::string&)>;
- static string apply_transform(string & self, const transform_fn & fn) {
- for (auto & part : self.parts) {
- part.val = fn(part.val);
- }
- return self;
- }
- string string::uppercase() {
- return apply_transform(*this, [](const std::string & s) {
- std::string res = s;
- std::transform(res.begin(), res.end(), res.begin(), ::toupper);
- return res;
- });
- }
- string string::lowercase() {
- return apply_transform(*this, [](const std::string & s) {
- std::string res = s;
- std::transform(res.begin(), res.end(), res.begin(), ::tolower);
- return res;
- });
- }
- string string::capitalize() {
- return apply_transform(*this, [](const std::string & s) {
- if (s.empty()) return s;
- std::string res = s;
- res[0] = ::toupper(static_cast<unsigned char>(res[0]));
- std::transform(res.begin() + 1, res.end(), res.begin() + 1, ::tolower);
- return res;
- });
- }
- string string::titlecase() {
- return apply_transform(*this, [](const std::string & s) {
- std::string res = s;
- bool capitalize_next = true;
- for (char &c : res) {
- if (isspace(static_cast<unsigned char>(c))) {
- capitalize_next = true;
- } else if (capitalize_next) {
- c = ::toupper(static_cast<unsigned char>(c));
- capitalize_next = false;
- } else {
- c = ::tolower(static_cast<unsigned char>(c));
- }
- }
- return res;
- });
- }
- string string::strip(bool left, bool right, std::optional<const std::string_view> chars) {
- static auto strip_part = [](const std::string & s, bool left, bool right, std::optional<const std::string_view> chars) -> std::string {
- size_t start = 0;
- size_t end = s.length();
- auto match_char = [&chars](unsigned char c) -> bool {
- return chars ? (*chars).find(c) != std::string::npos : isspace(c);
- };
- if (left) {
- while (start < end && match_char(static_cast<unsigned char>(s[start]))) {
- ++start;
- }
- }
- if (right) {
- while (end > start && match_char(static_cast<unsigned char>(s[end - 1]))) {
- --end;
- }
- }
- return s.substr(start, end - start);
- };
- if (parts.empty()) {
- return *this;
- }
- if (left) {
- for (size_t i = 0; i < parts.size(); ++i) {
- parts[i].val = strip_part(parts[i].val, true, false, chars);
- if (parts[i].val.empty()) {
- // remove empty part
- parts.erase(parts.begin() + i);
- --i;
- continue;
- } else {
- break;
- }
- }
- }
- if (right) {
- for (size_t i = parts.size(); i-- > 0;) {
- parts[i].val = strip_part(parts[i].val, false, true, chars);
- if (parts[i].val.empty()) {
- // remove empty part
- parts.erase(parts.begin() + i);
- continue;
- } else {
- break;
- }
- }
- }
- return *this;
- }
- } // namespace jinja
|