Ported a few helper methods from my String implementation in rcpp_framework.

This commit is contained in:
Relintai 2022-06-26 03:38:28 +02:00
parent 50faba808b
commit 2a9b32847f
3 changed files with 434 additions and 0 deletions

View File

@ -1077,6 +1077,22 @@ String String::hex_encode_buffer(const uint8_t *p_buffer, int p_len) {
return ret;
}
String String::bool_num(bool p_val) {
if (p_val) {
return "1";
} else {
return "0";
}
}
String String::bool_str(bool p_val) {
if (p_val) {
return "true";
} else {
return "false";
}
}
String String::chr(CharType p_char) {
CharType c[2] = { p_char, 0 };
return String(c);
@ -1857,6 +1873,26 @@ int String::to_int() const {
return integer * sign;
}
bool String::to_bool() const {
if (length() == 0) {
return false;
}
if (is_numeric()) {
return to_int() != 0;
}
return to_lower() == "true";
}
uint32_t String::to_uint() const {
if (is_numeric()) {
return static_cast<uint32_t>(to_int());
}
return 0;
}
int64_t String::to_int64() const {
if (length() == 0) {
return 0;
@ -1940,6 +1976,40 @@ bool String::is_numeric() const {
return true; // TODO: Use the parser below for this instead
};
bool String::is_zero() const {
int size = length();
if (size == 0) {
return false;
}
int starti = 0;
if (operator[](0) == '-') {
starti += 1;
}
bool had_dot = false;
for (int i = starti; i < size; ++i) {
CharType c = operator[](i);
if (c == '.') {
if (!had_dot) {
had_dot = true;
continue;
} else {
return false;
}
}
if (c != '0') {
return false;
}
}
return true;
}
template <class C>
static double built_in_strtod(
/* A decimal ASCII floating-point number,
@ -2431,6 +2501,20 @@ String String::substr(int p_from, int p_chars) const {
return s;
}
String String::substr_index(const int start_index, const int end_index) const {
int s = length();
if (start_index < 0 || start_index >= s || end_index < 0 || start_index >= s) {
return "";
}
if (start_index > end_index) {
return "";
}
return substr(start_index, end_index - start_index);
}
int String::find_last(const String &p_str) const {
return rfind(p_str);
}
@ -2723,6 +2807,66 @@ int String::rfindn(const String &p_str, int p_from) const {
return -1;
}
int String::find_first_difference_index(const String &p_str) const {
const int olen = p_str.length();
const int len = length();
const int c = len < olen ? len : olen;
const CharType *p = c_str();
const CharType *op = p_str.c_str();
for (int i = 0; i < c; ++i) {
if (p[i] != op[i]) {
return i;
}
}
return c;
}
bool String::is_word_at(const int index, const char *p_str) const {
int size = length();
ERR_FAIL_INDEX_V(index, size, false);
int i = 0;
while (p_str[i] != '\0') {
int iind = index + i;
if (iind >= size) {
return false;
}
if (operator[](iind) != p_str[i]) {
return false;
}
++i;
}
return true;
}
bool String::is_word_at(const int index, const String &p_str) const {
int size = length();
ERR_FAIL_INDEX_V(index, size, false);
if (index + p_str.length() >= size) {
return false;
}
for (int i = 0; i < p_str.length(); ++i) {
int iind = index + i;
if (operator[](iind) != p_str[i]) {
return false;
}
}
return true;
}
bool String::ends_with(const String &p_string) const {
int l = p_string.length();
if (l > length()) {
@ -3078,6 +3222,11 @@ String String::replacen(const String &p_key, const String &p_with) const {
return new_string;
}
String String::newline_to_br() const {
String r = replace("\r\n", "<br>");
return r.replace("\n", "<br>");
}
String String::repeat(int p_count) const {
ERR_FAIL_COND_V_MSG(p_count < 0, "", "Parameter count should be a positive number.");
@ -3333,6 +3482,156 @@ String String::simplify_path() const {
return drive + s;
}
String String::append_path(const char *path) const {
if (path[0] == '\0') {
return *this;
}
String ret = *this;
int size = length();
if (size == 0) {
ret += path;
return ret;
}
int sindex = 0;
char ch = path[sindex];
while (ch == '/' || ch == '\\') {
if (ch == '\0') {
return ret;
}
ch = path[++sindex];
}
// /////folder
// ^ (sindex)
if (ret.ends_with("/") || ret.ends_with("\\")) {
ret += &path[sindex];
} else {
if (sindex > 0) {
ret += '/';
ret += &path[sindex - 1];
} else {
ret += '/';
ret += &path[sindex];
}
}
return ret;
}
String String::append_path(const String &path) const {
if (path.length() == 0) {
return *this;
}
int size = length();
if (size == 0) {
return path;
}
int sindex = 0;
int ts = path.size() - 1;
char ch = path[sindex];
while (ch == '/' || ch == '\\') {
if (sindex == ts) {
return *this;
}
ch = path[++sindex];
}
String ret = *this;
// /////folder
// ^ (sindex)
if (ret.ends_with("/") || ret.ends_with("\\")) {
ret += &path[sindex];
} else {
if (sindex > 0) {
ret += '/';
ret += &path[sindex - 1];
} else {
ret += '/';
ret += &path[sindex];
}
}
return ret;
}
String String::path_clean_end_slash() const {
// _size > 1, so if root is given ("/"), it will not be removed
String ret = *this;
while (ret.length() > 1 && (ret.ends_with("/") || ret.ends_with("\\"))) {
ret.resize(length() - 1);
}
return ret;
}
String String::path_ensure_end_slash() const {
// Don't add if empty string, as it would make it root on linux, which can easily become a serious bug
String ret = *this;
if (ret.length() == 0) {
return ret;
}
if (!(ret.ends_with("/") || ret.ends_with("\\"))) {
ret += "/";
}
return ret;
}
String String::path_get_prev_dir() const {
int size = length();
if (size == 0) {
return "/";
}
int seind = size - 1;
while (seind > 0 && (operator[](seind) == '/' || operator[](seind) == '\\')) {
--seind;
}
if (seind == 0) {
// /////////
// or
// a///////
// no prev dir
return "/";
}
// fol/fol2/fol3//
// ^ (seind)
while (seind > 0 && (operator[](seind) != '/' && operator[](seind) != '\\')) {
--seind;
}
// fol/fol2/fol3//
// ^ (seind)
//--seind;
if (seind <= 0) {
return "/";
}
return substr_index(0, seind);
}
static int _humanize_digits(int p_num) {
if (p_num < 100) {
return 2;
@ -3845,6 +4144,63 @@ bool String::is_valid_float() const {
return numbers_found;
}
bool String::is_valid_bool() const {
int size = length();
if (size == 1) {
CharType c = ptr()[0];
if (c == '0') {
return true;
} else if (c == '1') {
return true;
}
return false;
} else if (size == 4) {
String l = to_lower();
const CharType *p = l.ptr();
if (p[0] == 't' && p[1] == 'r' && p[2] == 'u' && p[3] == 'e') {
return true;
} else {
return false;
}
} else if (size == 5) {
String l = to_lower();
const CharType *p = l.ptr();
if (p[0] == 'f' && p[1] == 'a' && p[2] == 'l' && p[3] == 's' && p[3] == 'e') {
return true;
} else {
return false;
}
}
return false;
}
bool String::is_valid_unsigned_integer() const {
int len = length();
if (len == 0) {
return false;
}
int from = 0;
if (len != 1 && (operator[](0) == '+')) {
from++;
}
for (int i = from; i < len; i++) {
if (operator[](i) < '0' || operator[](i) > '9') {
return false; // no start with number plz
}
}
return true;
}
String String::path_to_file(const String &p_path) const {
// Don't get base dir for src, this is expected to be a dir already.
String src = this->replace("\\", "/");

View File

@ -202,6 +202,8 @@ public:
/* complex helpers */
String substr(int p_from, int p_chars = -1) const;
String substr_index(const int p_start_index, const int p_end_index) const; //end_index is not included
int find(const String &p_str, int p_from = 0) const; ///< return <0 if failed
int find(const char *p_str, int p_from = 0) const; ///< return <0 if failed
int find_char(const CharType &p_char, int p_from = 0) const; ///< return <0 if failed
@ -210,33 +212,52 @@ public:
int rfind(const String &p_str, int p_from = -1) const; ///< return <0 if failed
int rfindn(const String &p_str, int p_from = -1) const; ///< return <0 if failed, case insensitive
int findmk(const Vector<String> &p_keys, int p_from = 0, int *r_key = nullptr) const; ///< return <0 if failed
int find_first_difference_index(const String &p_str) const;
bool is_word_at(const int p_index, const char *p_str) const;
bool is_word_at(const int p_index, const String &p_str) const;
bool match(const String &p_wildcard) const;
bool matchn(const String &p_wildcard) const;
bool begins_with(const String &p_string) const;
bool begins_with(const char *p_string) const;
bool ends_with(const String &p_string) const;
bool is_enclosed_in(const String &p_string) const;
bool is_subsequence_of(const String &p_string) const;
bool is_subsequence_ofi(const String &p_string) const;
bool is_quoted() const;
Vector<String> bigrams() const;
float similarity(const String &p_string) const;
String format(const Variant &values, String placeholder = "{_}") const;
String replace_first(const String &p_key, const String &p_with) const;
String replace(const String &p_key, const String &p_with) const;
String replace(const char *p_key, const char *p_with) const;
String replacen(const String &p_key, const String &p_with) const;
String newline_to_br() const;
String repeat(int p_count) const;
String insert(int p_at_pos, const String &p_string) const;
String pad_decimals(int p_digits) const;
String pad_zeros(int p_digits) const;
String trim_prefix(const String &p_prefix) const;
String trim_suffix(const String &p_suffix) const;
String lpad(int min_length, const String &character = " ") const;
String rpad(int min_length, const String &character = " ") const;
String sprintf(const Array &values, bool *error) const;
String quote(String quotechar = "\"") const;
String unquote() const;
static String num(double p_num, int p_decimals = -1);
static String num_scientific(double p_num);
static String num_real(double p_num);
@ -245,11 +266,18 @@ public:
static String chr(CharType p_char);
static String md5(const uint8_t *p_md5);
static String hex_encode_buffer(const uint8_t *p_buffer, int p_len);
static String bool_num(bool p_val);
static String bool_str(bool p_val);
bool is_numeric() const;
bool is_zero() const;
double to_double() const;
float to_float() const;
int hex_to_int(bool p_with_prefix = true) const;
int to_int() const;
bool to_bool() const;
uint32_t to_uint() const;
int64_t hex_to_int64(bool p_with_prefix = true) const;
int64_t bin_to_int64(bool p_with_prefix = true) const;
@ -328,6 +356,11 @@ public:
String get_file() const;
static String humanize_size(uint64_t p_size);
String simplify_path() const;
String append_path(const char *p_path) const;
String append_path(const String &p_path) const;
String path_clean_end_slash() const;
String path_ensure_end_slash() const;
String path_get_prev_dir() const;
String xml_escape(bool p_escape_quotes = false) const;
String xml_unescape() const;
@ -356,6 +389,8 @@ public:
bool is_valid_html_color() const;
bool is_valid_ip_address() const;
bool is_valid_filename() const;
bool is_valid_bool() const;
bool is_valid_unsigned_integer() const;
/**
* The constructors must not depend on other overloads

View File

@ -273,12 +273,15 @@ struct _VariantCall {
VCALL_LOCALMEM3R(String, count);
VCALL_LOCALMEM3R(String, countn);
VCALL_LOCALMEM2R(String, substr);
VCALL_LOCALMEM2R(String, substr_index);
VCALL_LOCALMEM2R(String, get_slice);
VCALL_LOCALMEM2R(String, find);
VCALL_LOCALMEM1R(String, find_last);
VCALL_LOCALMEM2R(String, findn);
VCALL_LOCALMEM2R(String, rfind);
VCALL_LOCALMEM2R(String, rfindn);
VCALL_LOCALMEM1R(String, find_first_difference_index);
VCALL_LOCALMEM2R(String, is_word_at);
VCALL_LOCALMEM1R(String, match);
VCALL_LOCALMEM1R(String, matchn);
VCALL_LOCALMEM1R(String, begins_with);
@ -290,6 +293,7 @@ struct _VariantCall {
VCALL_LOCALMEM2R(String, format);
VCALL_LOCALMEM2R(String, replace);
VCALL_LOCALMEM2R(String, replacen);
VCALL_LOCALMEM0R(String, newline_to_br);
VCALL_LOCALMEM1R(String, repeat);
VCALL_LOCALMEM2R(String, insert);
VCALL_LOCALMEM0R(String, capitalize);
@ -326,6 +330,10 @@ struct _VariantCall {
VCALL_LOCALMEM0R(String, is_rel_path);
VCALL_LOCALMEM0R(String, get_base_dir);
VCALL_LOCALMEM0R(String, get_file);
VCALL_LOCALMEM1R(String, append_path);
VCALL_LOCALMEM0R(String, path_clean_end_slash);
VCALL_LOCALMEM0R(String, path_ensure_end_slash);
VCALL_LOCALMEM0R(String, path_get_prev_dir);
VCALL_LOCALMEM0R(String, xml_escape);
VCALL_LOCALMEM0R(String, xml_unescape);
VCALL_LOCALMEM0R(String, http_escape);
@ -343,8 +351,14 @@ struct _VariantCall {
VCALL_LOCALMEM0R(String, is_valid_html_color);
VCALL_LOCALMEM0R(String, is_valid_ip_address);
VCALL_LOCALMEM0R(String, is_valid_filename);
VCALL_LOCALMEM0R(String, is_valid_bool);
VCALL_LOCALMEM0R(String, is_valid_unsigned_integer);
VCALL_LOCALMEM0R(String, is_numeric);
VCALL_LOCALMEM0R(String, is_zero);
VCALL_LOCALMEM0RI(String, to_int, to_int64);
VCALL_LOCALMEM0R(String, to_float);
VCALL_LOCALMEM0R(String, to_bool);
VCALL_LOCALMEM0R(String, to_uint);
VCALL_LOCALMEM0RI(String, hex_to_int, hex_to_int64);
VCALL_LOCALMEM1R(String, pad_decimals);
VCALL_LOCALMEM1R(String, pad_zeros);
@ -1873,7 +1887,10 @@ void register_variant_methods() {
ADDFUNC1R(STRING, INT, String, nocasecmp_to, STRING, "to", varray());
ADDFUNC1R(STRING, INT, String, naturalnocasecmp_to, STRING, "to", varray());
ADDFUNC0R(STRING, INT, String, length, varray());
ADDFUNC2R(STRING, STRING, String, substr, INT, "from", INT, "len", varray(-1));
ADDFUNC2R(STRING, STRING, String, substr_index, INT, "start_index", INT, "end_index", varray());
ADDFUNC2R(STRING, STRING, String, get_slice, STRING, "delimiter", INT, "slice", varray());
ADDFUNC2R(STRING, INT, String, find, STRING, "what", INT, "from", varray(0));
@ -1885,6 +1902,11 @@ void register_variant_methods() {
ADDFUNC2R(STRING, INT, String, findn, STRING, "what", INT, "from", varray(0));
ADDFUNC2R(STRING, INT, String, rfind, STRING, "what", INT, "from", varray(-1));
ADDFUNC2R(STRING, INT, String, rfindn, STRING, "what", INT, "from", varray(-1));
ADDFUNC1R(STRING, INT, String, find_first_difference_index, STRING, "what", varray(0));
ADDFUNC2R(STRING, INT, String, is_word_at, INT, "index", STRING, "str", varray());
ADDFUNC1R(STRING, BOOL, String, match, STRING, "expr", varray());
ADDFUNC1R(STRING, BOOL, String, matchn, STRING, "expr", varray());
ADDFUNC1R(STRING, BOOL, String, begins_with, STRING, "text", varray());
@ -1897,6 +1919,9 @@ void register_variant_methods() {
ADDFUNC2R(STRING, STRING, String, format, NIL, "values", STRING, "placeholder", varray("{_}"));
ADDFUNC2R(STRING, STRING, String, replace, STRING, "what", STRING, "forwhat", varray());
ADDFUNC2R(STRING, STRING, String, replacen, STRING, "what", STRING, "forwhat", varray());
ADDFUNC0R(STRING, STRING, String, newline_to_br, varray());
ADDFUNC1R(STRING, STRING, String, repeat, INT, "count", varray());
ADDFUNC2R(STRING, STRING, String, insert, INT, "position", STRING, "what", varray());
ADDFUNC0R(STRING, STRING, String, capitalize, varray());
@ -1921,6 +1946,7 @@ void register_variant_methods() {
ADDFUNC1R(STRING, STRING, String, indent, STRING, "prefix", varray());
ADDFUNC0R(STRING, STRING, String, dedent, varray());
ADDFUNC2(STRING, NIL, String, erase, INT, "position", INT, "chars", varray());
ADDFUNC0R(STRING, INT, String, hash, varray());
ADDFUNC0R(STRING, STRING, String, md5_text, varray());
ADDFUNC0R(STRING, STRING, String, sha1_text, varray());
@ -1928,13 +1954,20 @@ void register_variant_methods() {
ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, md5_buffer, varray());
ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, sha1_buffer, varray());
ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, sha256_buffer, varray());
ADDFUNC0R(STRING, BOOL, String, empty, varray());
ADDFUNC1R(STRING, STRING, String, humanize_size, INT, "size", varray());
ADDFUNC0R(STRING, BOOL, String, is_abs_path, varray());
ADDFUNC0R(STRING, STRING, String, simplify_path, varray());
ADDFUNC0R(STRING, BOOL, String, is_rel_path, varray());
ADDFUNC0R(STRING, STRING, String, get_base_dir, varray());
ADDFUNC0R(STRING, STRING, String, get_file, varray());
ADDFUNC1R(STRING, STRING, String, append_path, STRING, "path", varray());
ADDFUNC0R(STRING, STRING, String, path_clean_end_slash, varray());
ADDFUNC0R(STRING, STRING, String, path_ensure_end_slash, varray());
ADDFUNC0R(STRING, STRING, String, path_get_prev_dir, varray());
ADDFUNC0R(STRING, STRING, String, xml_escape, varray());
ADDFUNC0R(STRING, STRING, String, xml_unescape, varray());
ADDFUNC0R(STRING, STRING, String, http_escape, varray());
@ -1945,6 +1978,7 @@ void register_variant_methods() {
ADDFUNC0R(STRING, STRING, String, percent_encode, varray());
ADDFUNC0R(STRING, STRING, String, percent_decode, varray());
ADDFUNC0R(STRING, STRING, String, validate_node_name, varray());
ADDFUNC0R(STRING, BOOL, String, is_valid_identifier, varray());
ADDFUNC0R(STRING, BOOL, String, is_valid_integer, varray());
ADDFUNC0R(STRING, BOOL, String, is_valid_float, varray());
@ -1952,8 +1986,17 @@ void register_variant_methods() {
ADDFUNC0R(STRING, BOOL, String, is_valid_html_color, varray());
ADDFUNC0R(STRING, BOOL, String, is_valid_ip_address, varray());
ADDFUNC0R(STRING, BOOL, String, is_valid_filename, varray());
ADDFUNC0R(STRING, BOOL, String, is_valid_bool, varray());
ADDFUNC0R(STRING, BOOL, String, is_valid_unsigned_integer, varray());
ADDFUNC0R(STRING, BOOL, String, is_numeric, varray());
ADDFUNC0R(STRING, BOOL, String, is_zero, varray());
ADDFUNC0R(STRING, INT, String, to_int, varray());
ADDFUNC0R(STRING, REAL, String, to_float, varray());
ADDFUNC0R(STRING, INT, String, to_bool, varray());
ADDFUNC0R(STRING, INT, String, to_uint, varray());
ADDFUNC0R(STRING, INT, String, hex_to_int, varray());
ADDFUNC1R(STRING, STRING, String, pad_decimals, INT, "digits", varray());
ADDFUNC1R(STRING, STRING, String, pad_zeros, INT, "digits", varray());