Add const char * overloads to String class
Co-authored-by: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com>
This commit is contained in:
parent
55b8724bd5
commit
d4154dbc55
5 changed files with 670 additions and 158 deletions
|
@ -1184,6 +1184,26 @@ int String::get_slice_count(const String &p_splitter) const {
|
||||||
return slices;
|
return slices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int String::get_slice_count(const char *p_splitter) const {
|
||||||
|
if (is_empty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (p_splitter == nullptr || *p_splitter == '\0') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
int slices = 1;
|
||||||
|
int splitter_length = strlen(p_splitter);
|
||||||
|
|
||||||
|
while ((pos = find(p_splitter, pos)) >= 0) {
|
||||||
|
slices++;
|
||||||
|
pos += splitter_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return slices;
|
||||||
|
}
|
||||||
|
|
||||||
String String::get_slice(const String &p_splitter, int p_slice) const {
|
String String::get_slice(const String &p_splitter, int p_slice) const {
|
||||||
if (is_empty() || p_splitter.is_empty()) {
|
if (is_empty() || p_splitter.is_empty()) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -1224,6 +1244,47 @@ String String::get_slice(const String &p_splitter, int p_slice) const {
|
||||||
return ""; //no find!
|
return ""; //no find!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String String::get_slice(const char *p_splitter, int p_slice) const {
|
||||||
|
if (is_empty() || p_splitter == nullptr || *p_splitter == '\0') {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
int prev_pos = 0;
|
||||||
|
//int slices=1;
|
||||||
|
if (p_slice < 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (find(p_splitter) == -1) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
int splitter_length = strlen(p_splitter);
|
||||||
|
while (true) {
|
||||||
|
pos = find(p_splitter, pos);
|
||||||
|
if (pos == -1) {
|
||||||
|
pos = length(); //reached end
|
||||||
|
}
|
||||||
|
|
||||||
|
int from = prev_pos;
|
||||||
|
//int to=pos;
|
||||||
|
|
||||||
|
if (p_slice == i) {
|
||||||
|
return substr(from, pos - from);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos == length()) { //reached end and no find
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += splitter_length;
|
||||||
|
prev_pos = pos;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""; //no find!
|
||||||
|
}
|
||||||
|
|
||||||
String String::get_slicec(char32_t p_splitter, int p_slice) const {
|
String String::get_slicec(char32_t p_splitter, int p_slice) const {
|
||||||
if (is_empty()) {
|
if (is_empty()) {
|
||||||
return String();
|
return String();
|
||||||
|
@ -1338,6 +1399,54 @@ Vector<String> String::split(const String &p_splitter, bool p_allow_empty, int p
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<String> String::split(const char *p_splitter, bool p_allow_empty, int p_maxsplit) const {
|
||||||
|
Vector<String> ret;
|
||||||
|
|
||||||
|
if (is_empty()) {
|
||||||
|
if (p_allow_empty) {
|
||||||
|
ret.push_back("");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int from = 0;
|
||||||
|
int len = length();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int end;
|
||||||
|
if (p_splitter == nullptr || *p_splitter == '\0') {
|
||||||
|
end = from + 1;
|
||||||
|
} else {
|
||||||
|
end = find(p_splitter, from);
|
||||||
|
if (end < 0) {
|
||||||
|
end = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p_allow_empty || (end > from)) {
|
||||||
|
if (p_maxsplit <= 0) {
|
||||||
|
ret.push_back(substr(from, end - from));
|
||||||
|
} else {
|
||||||
|
// Put rest of the string and leave cycle.
|
||||||
|
if (p_maxsplit == ret.size()) {
|
||||||
|
ret.push_back(substr(from, len));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, push items until positive limit is reached.
|
||||||
|
ret.push_back(substr(from, end - from));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end == len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
from = end + strlen(p_splitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int p_maxsplit) const {
|
Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int p_maxsplit) const {
|
||||||
Vector<String> ret;
|
Vector<String> ret;
|
||||||
const int len = length();
|
const int len = length();
|
||||||
|
@ -1380,6 +1489,49 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector<String> String::rsplit(const char *p_splitter, bool p_allow_empty, int p_maxsplit) const {
|
||||||
|
Vector<String> ret;
|
||||||
|
const int len = length();
|
||||||
|
const int splitter_length = strlen(p_splitter);
|
||||||
|
int remaining_len = len;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (remaining_len < splitter_length || (p_maxsplit > 0 && p_maxsplit == ret.size())) {
|
||||||
|
// no room for another splitter or hit max splits, push what's left and we're done
|
||||||
|
if (p_allow_empty || remaining_len > 0) {
|
||||||
|
ret.push_back(substr(0, remaining_len));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int left_edge;
|
||||||
|
if (p_splitter == nullptr || *p_splitter == '\0') {
|
||||||
|
left_edge = remaining_len - 1;
|
||||||
|
if (left_edge == 0) {
|
||||||
|
left_edge--; // Skip to the < 0 condition.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
left_edge = rfind(p_splitter, remaining_len - splitter_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left_edge < 0) {
|
||||||
|
// no more splitters, we're done
|
||||||
|
ret.push_back(substr(0, remaining_len));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int substr_start = left_edge + splitter_length;
|
||||||
|
if (p_allow_empty || substr_start < remaining_len) {
|
||||||
|
ret.push_back(substr(substr_start, remaining_len - substr_start));
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining_len = left_edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.reverse();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
Vector<double> String::split_floats(const String &p_splitter, bool p_allow_empty) const {
|
Vector<double> String::split_floats(const String &p_splitter, bool p_allow_empty) const {
|
||||||
Vector<double> ret;
|
Vector<double> ret;
|
||||||
int from = 0;
|
int from = 0;
|
||||||
|
@ -3087,23 +3239,20 @@ int String::find(const String &p_str, int p_from) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int String::find(const char *p_str, int p_from) const {
|
int String::find(const char *p_str, int p_from) const {
|
||||||
if (p_from < 0) {
|
if (p_from < 0 || !p_str) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int src_len = strlen(p_str);
|
||||||
|
|
||||||
const int len = length();
|
const int len = length();
|
||||||
|
|
||||||
if (len == 0) {
|
if (len == 0 || src_len == 0) {
|
||||||
return -1; // won't find anything!
|
return -1; // won't find anything!
|
||||||
}
|
}
|
||||||
|
|
||||||
const char32_t *src = get_data();
|
const char32_t *src = get_data();
|
||||||
|
|
||||||
int src_len = 0;
|
|
||||||
while (p_str[src_len] != '\0') {
|
|
||||||
src_len++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (src_len == 1) {
|
if (src_len == 1) {
|
||||||
const char32_t needle = p_str[0];
|
const char32_t needle = p_str[0];
|
||||||
|
|
||||||
|
@ -3238,6 +3387,46 @@ int String::findn(const String &p_str, int p_from) const {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int String::findn(const char *p_str, int p_from) const {
|
||||||
|
if (p_from < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int src_len = strlen(p_str);
|
||||||
|
|
||||||
|
if (src_len == 0 || length() == 0) {
|
||||||
|
return -1; // won't find anything!
|
||||||
|
}
|
||||||
|
|
||||||
|
const char32_t *srcd = get_data();
|
||||||
|
|
||||||
|
for (int i = p_from; i <= (length() - src_len); i++) {
|
||||||
|
bool found = true;
|
||||||
|
for (int j = 0; j < src_len; j++) {
|
||||||
|
int read_pos = i + j;
|
||||||
|
|
||||||
|
if (read_pos >= length()) {
|
||||||
|
ERR_PRINT("read_pos>=length()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char32_t src = _find_lower(srcd[read_pos]);
|
||||||
|
char32_t dst = _find_lower(p_str[j]);
|
||||||
|
|
||||||
|
if (src != dst) {
|
||||||
|
found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int String::rfind(const String &p_str, int p_from) const {
|
int String::rfind(const String &p_str, int p_from) const {
|
||||||
// establish a limit
|
// establish a limit
|
||||||
int limit = length() - p_str.length();
|
int limit = length() - p_str.length();
|
||||||
|
@ -3285,6 +3474,57 @@ int String::rfind(const String &p_str, int p_from) const {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int String::rfind(const char *p_str, int p_from) const {
|
||||||
|
const int source_length = length();
|
||||||
|
int substring_length = strlen(p_str);
|
||||||
|
|
||||||
|
if (source_length == 0 || substring_length == 0) {
|
||||||
|
return -1; // won't find anything!
|
||||||
|
}
|
||||||
|
|
||||||
|
// establish a limit
|
||||||
|
int limit = length() - substring_length;
|
||||||
|
if (limit < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// establish a starting point
|
||||||
|
int starting_point;
|
||||||
|
if (p_from < 0) {
|
||||||
|
starting_point = limit;
|
||||||
|
} else if (p_from > limit) {
|
||||||
|
starting_point = limit;
|
||||||
|
} else {
|
||||||
|
starting_point = p_from;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char32_t *source = get_data();
|
||||||
|
|
||||||
|
for (int i = starting_point; i >= 0; i--) {
|
||||||
|
bool found = true;
|
||||||
|
for (int j = 0; j < substring_length; j++) {
|
||||||
|
int read_pos = i + j;
|
||||||
|
|
||||||
|
if (read_pos >= source_length) {
|
||||||
|
ERR_PRINT("read_pos>=source_length");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char32_t key_needle = p_str[j];
|
||||||
|
if (source[read_pos] != key_needle) {
|
||||||
|
found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int String::rfindn(const String &p_str, int p_from) const {
|
int String::rfindn(const String &p_str, int p_from) const {
|
||||||
// establish a limit
|
// establish a limit
|
||||||
int limit = length() - p_str.length();
|
int limit = length() - p_str.length();
|
||||||
|
@ -3335,6 +3575,60 @@ int String::rfindn(const String &p_str, int p_from) const {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int String::rfindn(const char *p_str, int p_from) const {
|
||||||
|
const int source_length = length();
|
||||||
|
int substring_length = strlen(p_str);
|
||||||
|
|
||||||
|
if (source_length == 0 || substring_length == 0) {
|
||||||
|
return -1; // won't find anything!
|
||||||
|
}
|
||||||
|
|
||||||
|
// establish a limit
|
||||||
|
int limit = length() - substring_length;
|
||||||
|
if (limit < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// establish a starting point
|
||||||
|
int starting_point;
|
||||||
|
if (p_from < 0) {
|
||||||
|
starting_point = limit;
|
||||||
|
} else if (p_from > limit) {
|
||||||
|
starting_point = limit;
|
||||||
|
} else {
|
||||||
|
starting_point = p_from;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char32_t *source = get_data();
|
||||||
|
|
||||||
|
for (int i = starting_point; i >= 0; i--) {
|
||||||
|
bool found = true;
|
||||||
|
for (int j = 0; j < substring_length; j++) {
|
||||||
|
int read_pos = i + j;
|
||||||
|
|
||||||
|
if (read_pos >= source_length) {
|
||||||
|
ERR_PRINT("read_pos>=source_length");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char32_t key_needle = p_str[j];
|
||||||
|
int srcc = _find_lower(source[read_pos]);
|
||||||
|
int keyc = _find_lower(key_needle);
|
||||||
|
|
||||||
|
if (srcc != keyc) {
|
||||||
|
found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
bool String::ends_with(const String &p_string) const {
|
bool String::ends_with(const String &p_string) const {
|
||||||
int l = p_string.length();
|
int l = p_string.length();
|
||||||
if (l > length()) {
|
if (l > length()) {
|
||||||
|
@ -3357,6 +3651,31 @@ bool String::ends_with(const String &p_string) const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool String::ends_with(const char *p_string) const {
|
||||||
|
if (!p_string) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int l = strlen(p_string);
|
||||||
|
if (l > length()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char32_t *s = &operator[](length() - l);
|
||||||
|
|
||||||
|
for (int i = 0; i < l; i++) {
|
||||||
|
if (static_cast<char32_t>(p_string[i]) != s[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool String::begins_with(const String &p_string) const {
|
bool String::begins_with(const String &p_string) const {
|
||||||
int l = p_string.length();
|
int l = p_string.length();
|
||||||
if (l > length()) {
|
if (l > length()) {
|
||||||
|
@ -3380,11 +3699,11 @@ bool String::begins_with(const String &p_string) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool String::begins_with(const char *p_string) const {
|
bool String::begins_with(const char *p_string) const {
|
||||||
int l = length();
|
|
||||||
if (!p_string) {
|
if (!p_string) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int l = length();
|
||||||
if (l == 0) {
|
if (l == 0) {
|
||||||
return *p_string == 0;
|
return *p_string == 0;
|
||||||
}
|
}
|
||||||
|
@ -3456,14 +3775,61 @@ int String::_count(const String &p_string, int p_from, int p_to, bool p_case_ins
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int String::_count(const char *p_string, int p_from, int p_to, bool p_case_insensitive) const {
|
||||||
|
int substring_length = strlen(p_string);
|
||||||
|
if (substring_length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const int source_length = length();
|
||||||
|
|
||||||
|
if (source_length < substring_length) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
String str;
|
||||||
|
int search_limit = p_to;
|
||||||
|
if (p_from >= 0 && p_to >= 0) {
|
||||||
|
if (p_to == 0) {
|
||||||
|
search_limit = source_length;
|
||||||
|
} else if (p_from >= p_to) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (p_from == 0 && search_limit == source_length) {
|
||||||
|
str = String();
|
||||||
|
str.copy_from_unchecked(&get_data()[0], source_length);
|
||||||
|
} else {
|
||||||
|
str = substr(p_from, search_limit - p_from);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int c = 0;
|
||||||
|
int idx = -1;
|
||||||
|
do {
|
||||||
|
idx = p_case_insensitive ? str.findn(p_string) : str.find(p_string);
|
||||||
|
if (idx != -1) {
|
||||||
|
str = str.substr(idx + substring_length, str.length() - substring_length);
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
} while (idx != -1);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
int String::count(const String &p_string, int p_from, int p_to) const {
|
int String::count(const String &p_string, int p_from, int p_to) const {
|
||||||
return _count(p_string, p_from, p_to, false);
|
return _count(p_string, p_from, p_to, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int String::count(const char *p_string, int p_from, int p_to) const {
|
||||||
|
return _count(p_string, p_from, p_to, false);
|
||||||
|
}
|
||||||
|
|
||||||
int String::countn(const String &p_string, int p_from, int p_to) const {
|
int String::countn(const String &p_string, int p_from, int p_to) const {
|
||||||
return _count(p_string, p_from, p_to, true);
|
return _count(p_string, p_from, p_to, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int String::countn(const char *p_string, int p_from, int p_to) const {
|
||||||
|
return _count(p_string, p_from, p_to, true);
|
||||||
|
}
|
||||||
|
|
||||||
bool String::_base_is_subsequence_of(const String &p_string, bool case_insensitive) const {
|
bool String::_base_is_subsequence_of(const String &p_string, bool case_insensitive) const {
|
||||||
int len = length();
|
int len = length();
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
|
@ -3673,6 +4039,16 @@ String String::replace_first(const String &p_key, const String &p_with) const {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String String::replace_first(const char *p_key, const char *p_with) const {
|
||||||
|
int pos = find(p_key);
|
||||||
|
if (pos >= 0) {
|
||||||
|
int substring_length = strlen(p_key);
|
||||||
|
return substr(0, pos) + p_with + substr(pos + substring_length, length());
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
String String::replacen(const String &p_key, const String &p_with) const {
|
String String::replacen(const String &p_key, const String &p_with) const {
|
||||||
String new_string;
|
String new_string;
|
||||||
int search_from = 0;
|
int search_from = 0;
|
||||||
|
@ -3692,6 +4068,31 @@ String String::replacen(const String &p_key, const String &p_with) const {
|
||||||
return new_string;
|
return new_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String String::replacen(const char *p_key, const char *p_with) const {
|
||||||
|
String new_string;
|
||||||
|
int search_from = 0;
|
||||||
|
int result = 0;
|
||||||
|
int substring_length = strlen(p_key);
|
||||||
|
|
||||||
|
if (substring_length == 0) {
|
||||||
|
return *this; // there's nothing to match or substitute
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((result = findn(p_key, search_from)) >= 0) {
|
||||||
|
new_string += substr(search_from, result - search_from);
|
||||||
|
new_string += p_with;
|
||||||
|
search_from = result + substring_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (search_from == 0) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_string += substr(search_from, length() - search_from);
|
||||||
|
|
||||||
|
return new_string;
|
||||||
|
}
|
||||||
|
|
||||||
String String::repeat(int p_count) const {
|
String String::repeat(int p_count) const {
|
||||||
ERR_FAIL_COND_V_MSG(p_count < 0, "", "Parameter count should be a positive number.");
|
ERR_FAIL_COND_V_MSG(p_count < 0, "", "Parameter count should be a positive number.");
|
||||||
|
|
||||||
|
@ -4420,6 +4821,15 @@ String String::trim_prefix(const String &p_prefix) const {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String String::trim_prefix(const char *p_prefix) const {
|
||||||
|
String s = *this;
|
||||||
|
if (s.begins_with(p_prefix)) {
|
||||||
|
int prefix_length = strlen(p_prefix);
|
||||||
|
return s.substr(prefix_length, s.length() - prefix_length);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
String String::trim_suffix(const String &p_suffix) const {
|
String String::trim_suffix(const String &p_suffix) const {
|
||||||
String s = *this;
|
String s = *this;
|
||||||
if (s.ends_with(p_suffix)) {
|
if (s.ends_with(p_suffix)) {
|
||||||
|
@ -4428,6 +4838,14 @@ String String::trim_suffix(const String &p_suffix) const {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String String::trim_suffix(const char *p_suffix) const {
|
||||||
|
String s = *this;
|
||||||
|
if (s.ends_with(p_suffix)) {
|
||||||
|
return s.substr(0, s.length() - strlen(p_suffix));
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
bool String::is_valid_int() const {
|
bool String::is_valid_int() const {
|
||||||
int len = length();
|
int len = length();
|
||||||
|
|
||||||
|
|
|
@ -198,6 +198,7 @@ class String {
|
||||||
|
|
||||||
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
|
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
|
||||||
int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const;
|
int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const;
|
||||||
|
int _count(const char *p_string, int p_from, int p_to, bool p_case_insensitive) const;
|
||||||
String _camelcase_to_underscore() const;
|
String _camelcase_to_underscore() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -288,14 +289,18 @@ public:
|
||||||
int find(const char *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 char32_t &p_char, int p_from = 0) const; ///< return <0 if failed
|
int find_char(const char32_t &p_char, int p_from = 0) const; ///< return <0 if failed
|
||||||
int findn(const String &p_str, int p_from = 0) const; ///< return <0 if failed, case insensitive
|
int findn(const String &p_str, int p_from = 0) const; ///< return <0 if failed, case insensitive
|
||||||
|
int findn(const char *p_str, int p_from = 0) const; ///< return <0 if failed
|
||||||
int rfind(const String &p_str, int p_from = -1) const; ///< return <0 if failed
|
int rfind(const String &p_str, int p_from = -1) const; ///< return <0 if failed
|
||||||
|
int rfind(const char *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 rfindn(const String &p_str, int p_from = -1) const; ///< return <0 if failed, case insensitive
|
||||||
|
int rfindn(const char *p_str, int p_from = -1) const; ///< return <0 if failed
|
||||||
int findmk(const Vector<String> &p_keys, int p_from = 0, int *r_key = nullptr) const; ///< return <0 if failed
|
int findmk(const Vector<String> &p_keys, int p_from = 0, int *r_key = nullptr) const; ///< return <0 if failed
|
||||||
bool match(const String &p_wildcard) const;
|
bool match(const String &p_wildcard) const;
|
||||||
bool matchn(const String &p_wildcard) const;
|
bool matchn(const String &p_wildcard) const;
|
||||||
bool begins_with(const String &p_string) const;
|
bool begins_with(const String &p_string) const;
|
||||||
bool begins_with(const char *p_string) const;
|
bool begins_with(const char *p_string) const;
|
||||||
bool ends_with(const String &p_string) const;
|
bool ends_with(const String &p_string) const;
|
||||||
|
bool ends_with(const char *p_string) const;
|
||||||
bool is_enclosed_in(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_of(const String &p_string) const;
|
||||||
bool is_subsequence_ofn(const String &p_string) const;
|
bool is_subsequence_ofn(const String &p_string) const;
|
||||||
|
@ -304,9 +309,11 @@ public:
|
||||||
float similarity(const String &p_string) const;
|
float similarity(const String &p_string) const;
|
||||||
String format(const Variant &values, const String &placeholder = "{_}") const;
|
String format(const Variant &values, const String &placeholder = "{_}") const;
|
||||||
String replace_first(const String &p_key, const String &p_with) const;
|
String replace_first(const String &p_key, const String &p_with) const;
|
||||||
|
String replace_first(const char *p_key, const char *p_with) const;
|
||||||
String replace(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 replace(const char *p_key, const char *p_with) const;
|
||||||
String replacen(const String &p_key, const String &p_with) const;
|
String replacen(const String &p_key, const String &p_with) const;
|
||||||
|
String replacen(const char *p_key, const char *p_with) const;
|
||||||
String repeat(int p_count) const;
|
String repeat(int p_count) const;
|
||||||
String reverse() const;
|
String reverse() const;
|
||||||
String insert(int p_at_pos, const String &p_string) const;
|
String insert(int p_at_pos, const String &p_string) const;
|
||||||
|
@ -314,7 +321,9 @@ public:
|
||||||
String pad_decimals(int p_digits) const;
|
String pad_decimals(int p_digits) const;
|
||||||
String pad_zeros(int p_digits) const;
|
String pad_zeros(int p_digits) const;
|
||||||
String trim_prefix(const String &p_prefix) const;
|
String trim_prefix(const String &p_prefix) const;
|
||||||
|
String trim_prefix(const char *p_prefix) const;
|
||||||
String trim_suffix(const String &p_suffix) const;
|
String trim_suffix(const String &p_suffix) const;
|
||||||
|
String trim_suffix(const char *p_suffix) const;
|
||||||
String lpad(int min_length, const String &character = " ") const;
|
String lpad(int min_length, const String &character = " ") const;
|
||||||
String rpad(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 sprintf(const Array &values, bool *error) const;
|
||||||
|
@ -353,11 +362,15 @@ public:
|
||||||
|
|
||||||
String get_with_code_lines() const;
|
String get_with_code_lines() const;
|
||||||
int get_slice_count(const String &p_splitter) const;
|
int get_slice_count(const String &p_splitter) const;
|
||||||
|
int get_slice_count(const char *p_splitter) const;
|
||||||
String get_slice(const String &p_splitter, int p_slice) const;
|
String get_slice(const String &p_splitter, int p_slice) const;
|
||||||
|
String get_slice(const char *p_splitter, int p_slice) const;
|
||||||
String get_slicec(char32_t p_splitter, int p_slice) const;
|
String get_slicec(char32_t p_splitter, int p_slice) const;
|
||||||
|
|
||||||
Vector<String> split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
|
Vector<String> split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
|
||||||
|
Vector<String> split(const char *p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
|
||||||
Vector<String> rsplit(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
|
Vector<String> rsplit(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
|
||||||
|
Vector<String> rsplit(const char *p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
|
||||||
Vector<String> split_spaces() const;
|
Vector<String> split_spaces() const;
|
||||||
Vector<double> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
|
Vector<double> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
|
||||||
Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
|
Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
|
||||||
|
@ -372,7 +385,9 @@ public:
|
||||||
String to_lower() const;
|
String to_lower() const;
|
||||||
|
|
||||||
int count(const String &p_string, int p_from = 0, int p_to = 0) const;
|
int count(const String &p_string, int p_from = 0, int p_to = 0) const;
|
||||||
|
int count(const char *p_string, int p_from = 0, int p_to = 0) const;
|
||||||
int countn(const String &p_string, int p_from = 0, int p_to = 0) const;
|
int countn(const String &p_string, int p_from = 0, int p_to = 0) const;
|
||||||
|
int countn(const char *p_string, int p_from = 0, int p_to = 0) const;
|
||||||
|
|
||||||
String left(int p_len) const;
|
String left(int p_len) const;
|
||||||
String right(int p_len) const;
|
String right(int p_len) const;
|
||||||
|
|
|
@ -1648,19 +1648,19 @@ static void _register_variant_builtin_methods() {
|
||||||
bind_string_method(filenocasecmp_to, sarray("to"), varray());
|
bind_string_method(filenocasecmp_to, sarray("to"), varray());
|
||||||
bind_string_method(length, sarray(), varray());
|
bind_string_method(length, sarray(), varray());
|
||||||
bind_string_method(substr, sarray("from", "len"), varray(-1));
|
bind_string_method(substr, sarray("from", "len"), varray(-1));
|
||||||
bind_string_method(get_slice, sarray("delimiter", "slice"), varray());
|
bind_string_methodv(get_slice, static_cast<String (String::*)(const String &, int) const>(&String::get_slice), sarray("delimiter", "slice"), varray());
|
||||||
bind_string_method(get_slicec, sarray("delimiter", "slice"), varray());
|
bind_string_method(get_slicec, sarray("delimiter", "slice"), varray());
|
||||||
bind_string_method(get_slice_count, sarray("delimiter"), varray());
|
bind_string_methodv(get_slice_count, static_cast<int (String::*)(const String &) const>(&String::get_slice_count), sarray("delimiter"), varray());
|
||||||
bind_string_methodv(find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0));
|
bind_string_methodv(find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0));
|
||||||
bind_string_method(count, sarray("what", "from", "to"), varray(0, 0));
|
bind_string_methodv(findn, static_cast<int (String::*)(const String &, int) const>(&String::findn), sarray("what", "from"), varray(0));
|
||||||
bind_string_method(countn, sarray("what", "from", "to"), varray(0, 0));
|
bind_string_methodv(count, static_cast<int (String::*)(const String &, int, int) const>(&String::count), sarray("what", "from", "to"), varray(0, 0));
|
||||||
bind_string_method(findn, sarray("what", "from"), varray(0));
|
bind_string_methodv(countn, static_cast<int (String::*)(const String &, int, int) const>(&String::countn), sarray("what", "from", "to"), varray(0, 0));
|
||||||
bind_string_method(rfind, sarray("what", "from"), varray(-1));
|
bind_string_methodv(rfind, static_cast<int (String::*)(const String &, int) const>(&String::rfind), sarray("what", "from"), varray(-1));
|
||||||
bind_string_method(rfindn, sarray("what", "from"), varray(-1));
|
bind_string_methodv(rfindn, static_cast<int (String::*)(const String &, int) const>(&String::rfindn), sarray("what", "from"), varray(-1));
|
||||||
bind_string_method(match, sarray("expr"), varray());
|
bind_string_method(match, sarray("expr"), varray());
|
||||||
bind_string_method(matchn, sarray("expr"), varray());
|
bind_string_method(matchn, sarray("expr"), varray());
|
||||||
bind_string_methodv(begins_with, static_cast<bool (String::*)(const String &) const>(&String::begins_with), sarray("text"), varray());
|
bind_string_methodv(begins_with, static_cast<bool (String::*)(const String &) const>(&String::begins_with), sarray("text"), varray());
|
||||||
bind_string_method(ends_with, sarray("text"), varray());
|
bind_string_methodv(ends_with, static_cast<bool (String::*)(const String &) const>(&String::ends_with), sarray("text"), varray());
|
||||||
bind_string_method(is_subsequence_of, sarray("text"), varray());
|
bind_string_method(is_subsequence_of, sarray("text"), varray());
|
||||||
bind_string_method(is_subsequence_ofn, sarray("text"), varray());
|
bind_string_method(is_subsequence_ofn, sarray("text"), varray());
|
||||||
bind_string_method(bigrams, sarray(), varray());
|
bind_string_method(bigrams, sarray(), varray());
|
||||||
|
@ -1668,7 +1668,7 @@ static void _register_variant_builtin_methods() {
|
||||||
|
|
||||||
bind_string_method(format, sarray("values", "placeholder"), varray("{_}"));
|
bind_string_method(format, sarray("values", "placeholder"), varray("{_}"));
|
||||||
bind_string_methodv(replace, static_cast<String (String::*)(const String &, const String &) const>(&String::replace), sarray("what", "forwhat"), varray());
|
bind_string_methodv(replace, static_cast<String (String::*)(const String &, const String &) const>(&String::replace), sarray("what", "forwhat"), varray());
|
||||||
bind_string_method(replacen, sarray("what", "forwhat"), varray());
|
bind_string_methodv(replacen, static_cast<String (String::*)(const String &, const String &) const>(&String::replacen), sarray("what", "forwhat"), varray());
|
||||||
bind_string_method(repeat, sarray("count"), varray());
|
bind_string_method(repeat, sarray("count"), varray());
|
||||||
bind_string_method(reverse, sarray(), varray());
|
bind_string_method(reverse, sarray(), varray());
|
||||||
bind_string_method(insert, sarray("position", "what"), varray());
|
bind_string_method(insert, sarray("position", "what"), varray());
|
||||||
|
@ -1677,8 +1677,8 @@ static void _register_variant_builtin_methods() {
|
||||||
bind_string_method(to_camel_case, sarray(), varray());
|
bind_string_method(to_camel_case, sarray(), varray());
|
||||||
bind_string_method(to_pascal_case, sarray(), varray());
|
bind_string_method(to_pascal_case, sarray(), varray());
|
||||||
bind_string_method(to_snake_case, sarray(), varray());
|
bind_string_method(to_snake_case, sarray(), varray());
|
||||||
bind_string_method(split, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
|
bind_string_methodv(split, static_cast<Vector<String> (String::*)(const String &, bool, int) const>(&String::split), sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
|
||||||
bind_string_method(rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
|
bind_string_methodv(rsplit, static_cast<Vector<String> (String::*)(const String &, bool, int) const>(&String::rsplit), sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
|
||||||
bind_string_method(split_floats, sarray("delimiter", "allow_empty"), varray(true));
|
bind_string_method(split_floats, sarray("delimiter", "allow_empty"), varray(true));
|
||||||
bind_string_method(join, sarray("parts"), varray());
|
bind_string_method(join, sarray("parts"), varray());
|
||||||
|
|
||||||
|
@ -1741,8 +1741,8 @@ static void _register_variant_builtin_methods() {
|
||||||
bind_string_method(rpad, sarray("min_length", "character"), varray(" "));
|
bind_string_method(rpad, sarray("min_length", "character"), varray(" "));
|
||||||
bind_string_method(pad_decimals, sarray("digits"), varray());
|
bind_string_method(pad_decimals, sarray("digits"), varray());
|
||||||
bind_string_method(pad_zeros, sarray("digits"), varray());
|
bind_string_method(pad_zeros, sarray("digits"), varray());
|
||||||
bind_string_method(trim_prefix, sarray("prefix"), varray());
|
bind_string_methodv(trim_prefix, static_cast<String (String::*)(const String &) const>(&String::trim_prefix), sarray("prefix"), varray());
|
||||||
bind_string_method(trim_suffix, sarray("suffix"), varray());
|
bind_string_methodv(trim_suffix, static_cast<String (String::*)(const String &) const>(&String::trim_suffix), sarray("suffix"), varray());
|
||||||
|
|
||||||
bind_string_method(to_ascii_buffer, sarray(), varray());
|
bind_string_method(to_ascii_buffer, sarray(), varray());
|
||||||
bind_string_method(to_utf8_buffer, sarray(), varray());
|
bind_string_method(to_utf8_buffer, sarray(), varray());
|
||||||
|
|
|
@ -360,18 +360,37 @@ TEST_CASE("[String] Substr") {
|
||||||
|
|
||||||
TEST_CASE("[String] Find") {
|
TEST_CASE("[String] Find") {
|
||||||
String s = "Pretty Woman Woman";
|
String s = "Pretty Woman Woman";
|
||||||
CHECK(s.find("tty") == 3);
|
MULTICHECK_STRING_EQ(s, find, "tty", 3);
|
||||||
CHECK(s.find("Wo", 9) == 13);
|
MULTICHECK_STRING_EQ(s, find, "Revenge of the Monster Truck", -1);
|
||||||
CHECK(s.find("Revenge of the Monster Truck") == -1);
|
MULTICHECK_STRING_INT_EQ(s, find, "Wo", 9, 13);
|
||||||
CHECK(s.rfind("man") == 15);
|
MULTICHECK_STRING_EQ(s, find, "", -1);
|
||||||
|
MULTICHECK_STRING_EQ(s, find, "Pretty Woman Woman", 0);
|
||||||
|
MULTICHECK_STRING_EQ(s, find, "WOMAN", -1);
|
||||||
|
MULTICHECK_STRING_INT_EQ(s, find, "", 9, -1);
|
||||||
|
|
||||||
|
MULTICHECK_STRING_EQ(s, rfind, "", -1);
|
||||||
|
MULTICHECK_STRING_EQ(s, rfind, "foo", -1);
|
||||||
|
MULTICHECK_STRING_EQ(s, rfind, "Pretty Woman Woman", 0);
|
||||||
|
MULTICHECK_STRING_EQ(s, rfind, "man", 15);
|
||||||
|
MULTICHECK_STRING_EQ(s, rfind, "WOMAN", -1);
|
||||||
|
MULTICHECK_STRING_INT_EQ(s, rfind, "", 15, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[String] Find no case") {
|
TEST_CASE("[String] Find no case") {
|
||||||
String s = "Pretty Whale Whale";
|
String s = "Pretty Whale Whale";
|
||||||
CHECK(s.findn("WHA") == 7);
|
MULTICHECK_STRING_EQ(s, findn, "WHA", 7);
|
||||||
CHECK(s.findn("WHA", 9) == 13);
|
MULTICHECK_STRING_INT_EQ(s, findn, "WHA", 9, 13);
|
||||||
CHECK(s.findn("Revenge of the Monster SawFish") == -1);
|
MULTICHECK_STRING_EQ(s, findn, "Revenge of the Monster SawFish", -1);
|
||||||
CHECK(s.rfindn("WHA") == 13);
|
MULTICHECK_STRING_EQ(s, findn, "", -1);
|
||||||
|
MULTICHECK_STRING_EQ(s, findn, "wha", 7);
|
||||||
|
MULTICHECK_STRING_EQ(s, findn, "Wha", 7);
|
||||||
|
MULTICHECK_STRING_INT_EQ(s, findn, "", 3, -1);
|
||||||
|
|
||||||
|
MULTICHECK_STRING_EQ(s, rfindn, "WHA", 13);
|
||||||
|
MULTICHECK_STRING_EQ(s, rfindn, "", -1);
|
||||||
|
MULTICHECK_STRING_EQ(s, rfindn, "wha", 13);
|
||||||
|
MULTICHECK_STRING_EQ(s, rfindn, "Wha", 13);
|
||||||
|
MULTICHECK_STRING_INT_EQ(s, rfindn, "", 13, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[String] Find MK") {
|
TEST_CASE("[String] Find MK") {
|
||||||
|
@ -392,11 +411,9 @@ TEST_CASE("[String] Find MK") {
|
||||||
|
|
||||||
TEST_CASE("[String] Find and replace") {
|
TEST_CASE("[String] Find and replace") {
|
||||||
String s = "Happy Birthday, Anna!";
|
String s = "Happy Birthday, Anna!";
|
||||||
s = s.replace("Birthday", "Halloween");
|
MULTICHECK_STRING_STRING_EQ(s, replace, "Birthday", "Halloween", "Happy Halloween, Anna!");
|
||||||
CHECK(s == "Happy Halloween, Anna!");
|
MULTICHECK_STRING_STRING_EQ(s, replace_first, "y", "Y", "HappY Birthday, Anna!");
|
||||||
|
MULTICHECK_STRING_STRING_EQ(s, replacen, "Y", "Y", "HappY BirthdaY, Anna!");
|
||||||
s = s.replace_first("H", "W");
|
|
||||||
CHECK(s == "Wappy Halloween, Anna!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[String] Insertion") {
|
TEST_CASE("[String] Insertion") {
|
||||||
|
@ -557,51 +574,76 @@ TEST_CASE("[String] String to float") {
|
||||||
|
|
||||||
TEST_CASE("[String] Slicing") {
|
TEST_CASE("[String] Slicing") {
|
||||||
String s = "Mars,Jupiter,Saturn,Uranus";
|
String s = "Mars,Jupiter,Saturn,Uranus";
|
||||||
|
|
||||||
const char *slices[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
|
const char *slices[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
|
||||||
for (int i = 0; i < s.get_slice_count(","); i++) {
|
MULTICHECK_GET_SLICE(s, ",", slices);
|
||||||
CHECK(s.get_slice(",", i) == slices[i]);
|
}
|
||||||
}
|
|
||||||
|
TEST_CASE("[String] Begins with") {
|
||||||
|
// Test cases for true:
|
||||||
|
MULTICHECK_STRING_EQ(String("res://foobar"), begins_with, "res://", true);
|
||||||
|
MULTICHECK_STRING_EQ(String("abc"), begins_with, "abc", true);
|
||||||
|
MULTICHECK_STRING_EQ(String("abc"), begins_with, "", true);
|
||||||
|
MULTICHECK_STRING_EQ(String(""), begins_with, "", true);
|
||||||
|
|
||||||
|
// Test cases for false:
|
||||||
|
MULTICHECK_STRING_EQ(String("res"), begins_with, "res://", false);
|
||||||
|
MULTICHECK_STRING_EQ(String("abcdef"), begins_with, "foo", false);
|
||||||
|
MULTICHECK_STRING_EQ(String("abc"), begins_with, "ax", false);
|
||||||
|
MULTICHECK_STRING_EQ(String(""), begins_with, "abc", false);
|
||||||
|
|
||||||
|
// Test "const char *" version also with nullptr.
|
||||||
|
String s("foo");
|
||||||
|
bool state = s.begins_with(nullptr) == false;
|
||||||
|
CHECK_MESSAGE(state, "nullptr check failed");
|
||||||
|
|
||||||
|
String empty("");
|
||||||
|
state = empty.begins_with(nullptr) == false;
|
||||||
|
CHECK_MESSAGE(state, "nullptr check with empty string failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("[String] Ends with") {
|
||||||
|
// Test cases for true:
|
||||||
|
MULTICHECK_STRING_EQ(String("res://foobar"), ends_with, "foobar", true);
|
||||||
|
MULTICHECK_STRING_EQ(String("abc"), ends_with, "abc", true);
|
||||||
|
MULTICHECK_STRING_EQ(String("abc"), ends_with, "", true);
|
||||||
|
MULTICHECK_STRING_EQ(String(""), ends_with, "", true);
|
||||||
|
|
||||||
|
// Test cases for false:
|
||||||
|
MULTICHECK_STRING_EQ(String("res"), ends_with, "res://", false);
|
||||||
|
MULTICHECK_STRING_EQ(String("abcdef"), ends_with, "foo", false);
|
||||||
|
MULTICHECK_STRING_EQ(String("abc"), ends_with, "ax", false);
|
||||||
|
MULTICHECK_STRING_EQ(String(""), ends_with, "abc", false);
|
||||||
|
|
||||||
|
// Test "const char *" version also with nullptr.
|
||||||
|
String s("foo");
|
||||||
|
bool state = s.ends_with(nullptr) == false;
|
||||||
|
CHECK_MESSAGE(state, "nullptr check failed");
|
||||||
|
|
||||||
|
String empty("");
|
||||||
|
state = empty.ends_with(nullptr) == false;
|
||||||
|
CHECK_MESSAGE(state, "nullptr check with empty string failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[String] Splitting") {
|
TEST_CASE("[String] Splitting") {
|
||||||
String s = "Mars,Jupiter,Saturn,Uranus";
|
String s = "Mars,Jupiter,Saturn,Uranus";
|
||||||
Vector<String> l;
|
|
||||||
|
|
||||||
const char *slices_l[3] = { "Mars", "Jupiter", "Saturn,Uranus" };
|
const char *slices_l[3] = { "Mars", "Jupiter", "Saturn,Uranus" };
|
||||||
|
MULTICHECK_SPLIT(s, split, ",", true, 2, slices_l, 3);
|
||||||
|
|
||||||
const char *slices_r[3] = { "Mars,Jupiter", "Saturn", "Uranus" };
|
const char *slices_r[3] = { "Mars,Jupiter", "Saturn", "Uranus" };
|
||||||
const char *slices_3[4] = { "t", "e", "s", "t" };
|
MULTICHECK_SPLIT(s, rsplit, ",", true, 2, slices_r, 3);
|
||||||
|
|
||||||
l = s.split(",", true, 2);
|
|
||||||
CHECK(l.size() == 3);
|
|
||||||
for (int i = 0; i < l.size(); i++) {
|
|
||||||
CHECK(l[i] == slices_l[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
l = s.rsplit(",", true, 2);
|
|
||||||
CHECK(l.size() == 3);
|
|
||||||
for (int i = 0; i < l.size(); i++) {
|
|
||||||
CHECK(l[i] == slices_r[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = "test";
|
s = "test";
|
||||||
l = s.split();
|
const char *slices_3[4] = { "t", "e", "s", "t" };
|
||||||
CHECK(l.size() == 4);
|
MULTICHECK_SPLIT(s, split, "", true, 0, slices_3, 4);
|
||||||
for (int i = 0; i < l.size(); i++) {
|
|
||||||
CHECK(l[i] == slices_3[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = "";
|
s = "";
|
||||||
l = s.split();
|
const char *slices_4[1] = { "" };
|
||||||
CHECK(l.size() == 1);
|
MULTICHECK_SPLIT(s, split, "", true, 0, slices_4, 1);
|
||||||
CHECK(l[0] == "");
|
MULTICHECK_SPLIT(s, split, "", false, 0, slices_4, 0);
|
||||||
|
|
||||||
l = s.split("", false);
|
|
||||||
CHECK(l.size() == 0);
|
|
||||||
|
|
||||||
s = "Mars Jupiter Saturn Uranus";
|
s = "Mars Jupiter Saturn Uranus";
|
||||||
const char *slices_s[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
|
const char *slices_s[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
|
||||||
l = s.split_spaces();
|
Vector<String> l = s.split_spaces();
|
||||||
for (int i = 0; i < l.size(); i++) {
|
for (int i = 0; i < l.size(); i++) {
|
||||||
CHECK(l[i] == slices_s[i]);
|
CHECK(l[i] == slices_s[i]);
|
||||||
}
|
}
|
||||||
|
@ -644,69 +686,6 @@ TEST_CASE("[String] Splitting") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct test_27_data {
|
|
||||||
char const *data;
|
|
||||||
char const *part;
|
|
||||||
bool expected;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_CASE("[String] Begins with") {
|
|
||||||
test_27_data tc[] = {
|
|
||||||
// Test cases for true:
|
|
||||||
{ "res://foobar", "res://", true },
|
|
||||||
{ "abc", "abc", true },
|
|
||||||
{ "abc", "", true },
|
|
||||||
{ "", "", true },
|
|
||||||
// Test cases for false:
|
|
||||||
{ "res", "res://", false },
|
|
||||||
{ "abcdef", "foo", false },
|
|
||||||
{ "abc", "ax", false },
|
|
||||||
{ "", "abc", false }
|
|
||||||
};
|
|
||||||
size_t count = sizeof(tc) / sizeof(tc[0]);
|
|
||||||
bool state = true;
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
String s = tc[i].data;
|
|
||||||
state = s.begins_with(tc[i].part) == tc[i].expected;
|
|
||||||
CHECK_MESSAGE(state, "first check failed at: ", i);
|
|
||||||
|
|
||||||
String sb = tc[i].part;
|
|
||||||
state = s.begins_with(sb) == tc[i].expected;
|
|
||||||
CHECK_MESSAGE(state, "second check failed at: ", i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test "const char *" version also with nullptr.
|
|
||||||
String s("foo");
|
|
||||||
state = s.begins_with(nullptr) == false;
|
|
||||||
CHECK_MESSAGE(state, "nullptr check failed");
|
|
||||||
|
|
||||||
String empty("");
|
|
||||||
state = empty.begins_with(nullptr) == false;
|
|
||||||
CHECK_MESSAGE(state, "nullptr check with empty string failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("[String] Ends with") {
|
|
||||||
test_27_data tc[] = {
|
|
||||||
// test cases for true:
|
|
||||||
{ "res://foobar", "foobar", true },
|
|
||||||
{ "abc", "abc", true },
|
|
||||||
{ "abc", "", true },
|
|
||||||
{ "", "", true },
|
|
||||||
// test cases for false:
|
|
||||||
{ "res", "res://", false },
|
|
||||||
{ "", "abc", false },
|
|
||||||
{ "abcdef", "foo", false },
|
|
||||||
{ "abc", "xc", false }
|
|
||||||
};
|
|
||||||
size_t count = sizeof(tc) / sizeof(tc[0]);
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
String s = tc[i].data;
|
|
||||||
String sb = tc[i].part;
|
|
||||||
bool state = s.ends_with(sb) == tc[i].expected;
|
|
||||||
CHECK_MESSAGE(state, "check failed at: ", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("[String] format") {
|
TEST_CASE("[String] format") {
|
||||||
const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
|
const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
|
||||||
|
|
||||||
|
@ -1498,39 +1477,62 @@ TEST_CASE("[String] Cyrillic to_lower()") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[String] Count and countn functionality") {
|
TEST_CASE("[String] Count and countn functionality") {
|
||||||
#define COUNT_TEST(x) \
|
String s = String("");
|
||||||
{ \
|
MULTICHECK_STRING_EQ(s, count, "Test", 0);
|
||||||
bool success = x; \
|
|
||||||
state = state && success; \
|
|
||||||
}
|
|
||||||
|
|
||||||
bool state = true;
|
s = "Test";
|
||||||
|
MULTICHECK_STRING_EQ(s, count, "", 0);
|
||||||
|
|
||||||
COUNT_TEST(String("").count("Test") == 0);
|
s = "Test";
|
||||||
COUNT_TEST(String("Test").count("") == 0);
|
MULTICHECK_STRING_EQ(s, count, "test", 0);
|
||||||
COUNT_TEST(String("Test").count("test") == 0);
|
|
||||||
COUNT_TEST(String("Test").count("TEST") == 0);
|
|
||||||
COUNT_TEST(String("TEST").count("TEST") == 1);
|
|
||||||
COUNT_TEST(String("Test").count("Test") == 1);
|
|
||||||
COUNT_TEST(String("aTest").count("Test") == 1);
|
|
||||||
COUNT_TEST(String("Testa").count("Test") == 1);
|
|
||||||
COUNT_TEST(String("TestTestTest").count("Test") == 3);
|
|
||||||
COUNT_TEST(String("TestTestTest").count("TestTest") == 1);
|
|
||||||
COUNT_TEST(String("TestGodotTestGodotTestGodot").count("Test") == 3);
|
|
||||||
|
|
||||||
COUNT_TEST(String("TestTestTestTest").count("Test", 4, 8) == 1);
|
s = "Test";
|
||||||
COUNT_TEST(String("TestTestTestTest").count("Test", 4, 12) == 2);
|
MULTICHECK_STRING_EQ(s, count, "TEST", 0);
|
||||||
COUNT_TEST(String("TestTestTestTest").count("Test", 4, 16) == 3);
|
|
||||||
COUNT_TEST(String("TestTestTestTest").count("Test", 4) == 3);
|
|
||||||
|
|
||||||
COUNT_TEST(String("Test").countn("test") == 1);
|
s = "TEST";
|
||||||
COUNT_TEST(String("Test").countn("TEST") == 1);
|
MULTICHECK_STRING_EQ(s, count, "TEST", 1);
|
||||||
COUNT_TEST(String("testTest-Testatest").countn("tEst") == 4);
|
|
||||||
COUNT_TEST(String("testTest-TeStatest").countn("tEsT", 4, 16) == 2);
|
|
||||||
|
|
||||||
CHECK(state);
|
s = "Test";
|
||||||
|
MULTICHECK_STRING_EQ(s, count, "Test", 1);
|
||||||
|
|
||||||
#undef COUNT_TEST
|
s = "aTest";
|
||||||
|
MULTICHECK_STRING_EQ(s, count, "Test", 1);
|
||||||
|
|
||||||
|
s = "Testa";
|
||||||
|
MULTICHECK_STRING_EQ(s, count, "Test", 1);
|
||||||
|
|
||||||
|
s = "TestTestTest";
|
||||||
|
MULTICHECK_STRING_EQ(s, count, "Test", 3);
|
||||||
|
|
||||||
|
s = "TestTestTest";
|
||||||
|
MULTICHECK_STRING_EQ(s, count, "TestTest", 1);
|
||||||
|
|
||||||
|
s = "TestGodotTestGodotTestGodot";
|
||||||
|
MULTICHECK_STRING_EQ(s, count, "Test", 3);
|
||||||
|
|
||||||
|
s = "TestTestTestTest";
|
||||||
|
MULTICHECK_STRING_INT_INT_EQ(s, count, "Test", 4, 8, 1);
|
||||||
|
|
||||||
|
s = "TestTestTestTest";
|
||||||
|
MULTICHECK_STRING_INT_INT_EQ(s, count, "Test", 4, 12, 2);
|
||||||
|
|
||||||
|
s = "TestTestTestTest";
|
||||||
|
MULTICHECK_STRING_INT_INT_EQ(s, count, "Test", 4, 16, 3);
|
||||||
|
|
||||||
|
s = "TestTestTestTest";
|
||||||
|
MULTICHECK_STRING_INT_EQ(s, count, "Test", 4, 3);
|
||||||
|
|
||||||
|
s = "Test";
|
||||||
|
MULTICHECK_STRING_EQ(s, countn, "test", 1);
|
||||||
|
|
||||||
|
s = "Test";
|
||||||
|
MULTICHECK_STRING_EQ(s, countn, "TEST", 1);
|
||||||
|
|
||||||
|
s = "testTest-Testatest";
|
||||||
|
MULTICHECK_STRING_EQ(s, countn, "tEst", 4);
|
||||||
|
|
||||||
|
s = "testTest-TeStatest";
|
||||||
|
MULTICHECK_STRING_INT_INT_EQ(s, countn, "tEsT", 4, 16, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[String] Bigrams") {
|
TEST_CASE("[String] Bigrams") {
|
||||||
|
@ -1703,9 +1705,19 @@ TEST_CASE("[String] Strip edges") {
|
||||||
|
|
||||||
TEST_CASE("[String] Trim") {
|
TEST_CASE("[String] Trim") {
|
||||||
String s = "aaaTestbbb";
|
String s = "aaaTestbbb";
|
||||||
CHECK(s.trim_prefix("aaa") == "Testbbb");
|
MULTICHECK_STRING_EQ(s, trim_prefix, "aaa", "Testbbb");
|
||||||
CHECK(s.trim_suffix("bbb") == "aaaTest");
|
MULTICHECK_STRING_EQ(s, trim_prefix, "Test", s);
|
||||||
CHECK(s.trim_suffix("Test") == s);
|
MULTICHECK_STRING_EQ(s, trim_prefix, "", s);
|
||||||
|
MULTICHECK_STRING_EQ(s, trim_prefix, "aaaTestbbb", "");
|
||||||
|
MULTICHECK_STRING_EQ(s, trim_prefix, "bbb", s);
|
||||||
|
MULTICHECK_STRING_EQ(s, trim_prefix, "AAA", s);
|
||||||
|
|
||||||
|
MULTICHECK_STRING_EQ(s, trim_suffix, "bbb", "aaaTest");
|
||||||
|
MULTICHECK_STRING_EQ(s, trim_suffix, "Test", s);
|
||||||
|
MULTICHECK_STRING_EQ(s, trim_suffix, "", s);
|
||||||
|
MULTICHECK_STRING_EQ(s, trim_suffix, "aaaTestbbb", "");
|
||||||
|
MULTICHECK_STRING_EQ(s, trim_suffix, "aaa", s);
|
||||||
|
MULTICHECK_STRING_EQ(s, trim_suffix, "BBB", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("[String] Right/Left") {
|
TEST_CASE("[String] Right/Left") {
|
||||||
|
|
|
@ -406,4 +406,71 @@ public:
|
||||||
#define SIGNAL_CHECK_FALSE(m_signal) CHECK(SignalWatcher::get_singleton()->check_false(m_signal));
|
#define SIGNAL_CHECK_FALSE(m_signal) CHECK(SignalWatcher::get_singleton()->check_false(m_signal));
|
||||||
#define SIGNAL_DISCARD(m_signal) SignalWatcher::get_singleton()->discard_signal(m_signal);
|
#define SIGNAL_DISCARD(m_signal) SignalWatcher::get_singleton()->discard_signal(m_signal);
|
||||||
|
|
||||||
|
#define MULTICHECK_STRING_EQ(m_obj, m_func, m_param1, m_eq) \
|
||||||
|
CHECK(m_obj.m_func(m_param1) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(U##m_param1) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(L##m_param1) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(String(m_param1)) == m_eq);
|
||||||
|
|
||||||
|
#define MULTICHECK_STRING_INT_EQ(m_obj, m_func, m_param1, m_param2, m_eq) \
|
||||||
|
CHECK(m_obj.m_func(m_param1, m_param2) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(U##m_param1, m_param2) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(L##m_param1, m_param2) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(String(m_param1), m_param2) == m_eq);
|
||||||
|
|
||||||
|
#define MULTICHECK_STRING_INT_INT_EQ(m_obj, m_func, m_param1, m_param2, m_param3, m_eq) \
|
||||||
|
CHECK(m_obj.m_func(m_param1, m_param2, m_param3) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(U##m_param1, m_param2, m_param3) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(L##m_param1, m_param2, m_param3) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(String(m_param1), m_param2, m_param3) == m_eq);
|
||||||
|
|
||||||
|
#define MULTICHECK_STRING_STRING_EQ(m_obj, m_func, m_param1, m_param2, m_eq) \
|
||||||
|
CHECK(m_obj.m_func(m_param1, m_param2) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(U##m_param1, U##m_param2) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(L##m_param1, L##m_param2) == m_eq); \
|
||||||
|
CHECK(m_obj.m_func(String(m_param1), String(m_param2)) == m_eq);
|
||||||
|
|
||||||
|
#define MULTICHECK_GET_SLICE(m_obj, m_param1, m_slices) \
|
||||||
|
for (int i = 0; i < m_obj.get_slice_count(m_param1); ++i) { \
|
||||||
|
CHECK(m_obj.get_slice(m_param1, i) == m_slices[i]); \
|
||||||
|
} \
|
||||||
|
for (int i = 0; i < m_obj.get_slice_count(U##m_param1); ++i) { \
|
||||||
|
CHECK(m_obj.get_slice(U##m_param1, i) == m_slices[i]); \
|
||||||
|
} \
|
||||||
|
for (int i = 0; i < m_obj.get_slice_count(L##m_param1); ++i) { \
|
||||||
|
CHECK(m_obj.get_slice(L##m_param1, i) == m_slices[i]); \
|
||||||
|
} \
|
||||||
|
for (int i = 0; i < m_obj.get_slice_count(String(m_param1)); ++i) { \
|
||||||
|
CHECK(m_obj.get_slice(String(m_param1), i) == m_slices[i]); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MULTICHECK_SPLIT(m_obj, m_func, m_param1, m_param2, m_param3, m_slices, m_expected_size) \
|
||||||
|
do { \
|
||||||
|
Vector<String> string_list; \
|
||||||
|
\
|
||||||
|
string_list = m_obj.m_func(m_param1, m_param2, m_param3); \
|
||||||
|
CHECK(m_expected_size == string_list.size()); \
|
||||||
|
for (int i = 0; i < string_list.size(); ++i) { \
|
||||||
|
CHECK(string_list[i] == m_slices[i]); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
string_list = m_obj.m_func(U##m_param1, m_param2, m_param3); \
|
||||||
|
CHECK(m_expected_size == string_list.size()); \
|
||||||
|
for (int i = 0; i < string_list.size(); ++i) { \
|
||||||
|
CHECK(string_list[i] == m_slices[i]); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
string_list = m_obj.m_func(L##m_param1, m_param2, m_param3); \
|
||||||
|
CHECK(m_expected_size == string_list.size()); \
|
||||||
|
for (int i = 0; i < string_list.size(); ++i) { \
|
||||||
|
CHECK(string_list[i] == m_slices[i]); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
string_list = m_obj.m_func(String(m_param1), m_param2, m_param3); \
|
||||||
|
CHECK(m_expected_size == string_list.size()); \
|
||||||
|
for (int i = 0; i < string_list.size(); ++i) { \
|
||||||
|
CHECK(string_list[i] == m_slices[i]); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#endif // TEST_MACROS_H
|
#endif // TEST_MACROS_H
|
||||||
|
|
Loading…
Reference in a new issue