@@ -925,7 +925,7 @@ String String::_camelcase_to_underscore() const {
925925}
926926
927927String String::capitalize () const {
928- String aux = _camelcase_to_underscore ().replace ( " _ " , " " ).strip_edges ();
928+ String aux = _camelcase_to_underscore ().replace_char ( ' _ ' , ' ' ).strip_edges ();
929929 String cap;
930930 for (int i = 0 ; i < aux.get_slice_count (" " ); i++) {
931931 String slice = aux.get_slicec (' ' , i);
@@ -954,7 +954,7 @@ String String::to_pascal_case() const {
954954}
955955
956956String String::to_snake_case () const {
957- return _camelcase_to_underscore ().replace ( " " , " _ " ).strip_edges ();
957+ return _camelcase_to_underscore ().replace_char ( ' ' , ' _ ' ).strip_edges ();
958958}
959959
960960String String::get_with_code_lines () const {
@@ -4199,6 +4199,117 @@ String String::replace_first(const char *p_key, const char *p_with) const {
41994199 return *this ;
42004200}
42014201
4202+ String String::replace_char (char32_t p_key, char32_t p_with) const {
4203+ ERR_FAIL_COND_V_MSG (p_with == 0 , *this , " `with` must not be the NUL character." );
4204+
4205+ if (p_key == 0 ) {
4206+ return *this ;
4207+ }
4208+
4209+ int len = length ();
4210+ if (len == 0 ) {
4211+ return *this ;
4212+ }
4213+
4214+ int index = 0 ;
4215+ const char32_t *old_ptr = ptr ();
4216+ for (; index < len; ++index) {
4217+ if (old_ptr[index] == p_key) {
4218+ break ;
4219+ }
4220+ }
4221+
4222+ // If no occurrence of `key` was found, return this.
4223+ if (index == len) {
4224+ return *this ;
4225+ }
4226+
4227+ // If we found at least one occurrence of `key`, create new string.
4228+ String new_string;
4229+ new_string.resize (len + 1 );
4230+ char32_t *new_ptr = new_string.ptrw ();
4231+
4232+ // Copy part of input before `key`.
4233+ memcpy (new_ptr, old_ptr, index * sizeof (char32_t ));
4234+
4235+ new_ptr[index] = p_with;
4236+
4237+ // Copy or replace rest of input.
4238+ for (++index; index < len; ++index) {
4239+ if (old_ptr[index] == p_key) {
4240+ new_ptr[index] = p_with;
4241+ } else {
4242+ new_ptr[index] = old_ptr[index];
4243+ }
4244+ }
4245+
4246+ new_ptr[index] = _null;
4247+
4248+ return new_string;
4249+ }
4250+
4251+ template <class T >
4252+ static String _replace_chars_common (const String &p_this, const T *p_keys, int p_keys_len, char32_t p_with) {
4253+ ERR_FAIL_COND_V_MSG (p_with == 0 , p_this, " `with` must not be the NUL character." );
4254+
4255+ // Delegate if p_keys is a single element.
4256+ if (p_keys_len == 1 ) {
4257+ return p_this.replace_char (*p_keys, p_with);
4258+ } else if (p_keys_len == 0 ) {
4259+ return p_this;
4260+ }
4261+
4262+ int len = p_this.length ();
4263+ if (len == 0 ) {
4264+ return p_this;
4265+ }
4266+
4267+ int index = 0 ;
4268+ const char32_t *old_ptr = p_this.ptr ();
4269+ for (; index < len; ++index) {
4270+ if (_contains_char (old_ptr[index], p_keys, p_keys_len)) {
4271+ break ;
4272+ }
4273+ }
4274+
4275+ // If no occurrence of `keys` was found, return this.
4276+ if (index == len) {
4277+ return p_this;
4278+ }
4279+
4280+ // If we found at least one occurrence of `keys`, create new string.
4281+ String new_string;
4282+ new_string.resize (len + 1 );
4283+ char32_t *new_ptr = new_string.ptrw ();
4284+
4285+ // Copy part of input before `key`.
4286+ memcpy (new_ptr, old_ptr, index * sizeof (char32_t ));
4287+
4288+ new_ptr[index] = p_with;
4289+
4290+ // Copy or replace rest of input.
4291+ for (++index; index < len; ++index) {
4292+ const char32_t old_char = old_ptr[index];
4293+ if (_contains_char (old_char, p_keys, p_keys_len)) {
4294+ new_ptr[index] = p_with;
4295+ } else {
4296+ new_ptr[index] = old_char;
4297+ }
4298+ }
4299+
4300+ new_ptr[index] = 0 ;
4301+
4302+ return new_string;
4303+ }
4304+
4305+ String String::replace_chars (const String &p_keys, char32_t p_with) const {
4306+ return _replace_chars_common (*this , p_keys.ptr (), p_keys.length (), p_with);
4307+ }
4308+
4309+ String String::replace_chars (const char *p_keys, char32_t p_with) const {
4310+ return _replace_chars_common (*this , p_keys, strlen (p_keys), p_with);
4311+ }
4312+
42024313String String::replacen (const String &p_key, const String &p_with) const {
42034314 return _replace_common (*this , p_key, p_with, true );
42044315}
@@ -4481,7 +4592,7 @@ String String::simplify_path() const {
44814592 }
44824593 }
44834594
4484- s = s.replace ( " \\ " , " / " );
4595+ s = s.replace_char ( ' \\ ' , ' / ' );
44854596 while (true ) { // in case of using 2 or more slash
44864597 String compare = s.replace (" //" , " /" );
44874598 if (s == compare) {
@@ -5124,8 +5235,8 @@ bool String::is_valid_float() const {
51245235
51255236String String::path_to_file (const String &p_path) const {
51265237 // Don't get base dir for src, this is expected to be a dir already.
5127- String src = replace ( " \\ " , " / " );
5128- String dst = p_path.replace ( " \\ " , " / " ).get_base_dir ();
5238+ String src = replace_char ( ' \\ ' , ' / ' );
5239+ String dst = p_path.replace_char ( ' \\ ' , ' / ' ).get_base_dir ();
51295240 String rel = src.path_to (dst);
51305241 if (rel == dst) { // failed
51315242 return p_path;
@@ -5135,8 +5246,8 @@ String String::path_to_file(const String &p_path) const {
51355246}
51365247
51375248String String::path_to (const String &p_path) const {
5138- String src = replace ( " \\ " , " / " );
5139- String dst = p_path.replace ( " \\ " , " / " );
5249+ String src = replace_char ( ' \\ ' , ' / ' );
5250+ String dst = p_path.replace_char ( ' \\ ' , ' / ' );
51405251 if (!src.ends_with (" /" )) {
51415252 src += " /" ;
51425253 }
0 commit comments