Merge pull request #92475 from AThousandShips/string_replace_char

Add `String::replace_char(s)` methods for performance and convenience
This commit is contained in:
Thaddeus Crews 2025-04-10 10:18:16 -05:00
commit cade15a163
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
67 changed files with 297 additions and 137 deletions

View file

@ -173,7 +173,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
if (dir->change_dir(path) == OK) { if (dir->change_dir(path) == OK) {
String cwd = dir->get_current_dir(); String cwd = dir->get_current_dir();
cwd = cwd.replace("\\", "/"); cwd = cwd.replace_char('\\', '/');
// Ensure that we end with a '/'. // Ensure that we end with a '/'.
// This is important to ensure that we do not wrongly localize the resource path // This is important to ensure that we do not wrongly localize the resource path
@ -591,7 +591,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
if (!OS::get_singleton()->get_resource_dir().is_empty()) { if (!OS::get_singleton()->get_resource_dir().is_empty()) {
// OS will call ProjectSettings->get_resource_path which will be empty if not overridden! // OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
// If the OS would rather use a specific location, then it will not be empty. // If the OS would rather use a specific location, then it will not be empty.
resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/"); resource_path = OS::get_singleton()->get_resource_dir().replace_char('\\', '/');
if (!resource_path.is_empty() && resource_path[resource_path.length() - 1] == '/') { if (!resource_path.is_empty() && resource_path[resource_path.length() - 1] == '/') {
resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end. resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
} }
@ -712,7 +712,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
while (true) { while (true) {
// Set the resource path early so things can be resolved when loading. // Set the resource path early so things can be resolved when loading.
resource_path = current_dir; resource_path = current_dir;
resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case. resource_path = resource_path.replace_char('\\', '/'); // Windows path to Unix path just in case.
err = _load_settings_text_or_binary(current_dir.path_join("project.godot"), current_dir.path_join("project.binary")); err = _load_settings_text_or_binary(current_dir.path_join("project.godot"), current_dir.path_join("project.binary"));
if (err == OK && !p_ignore_override) { if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails. // Optional, we don't mind if it fails.

View file

@ -32,11 +32,11 @@
String DocData::get_default_value_string(const Variant &p_value) { String DocData::get_default_value_string(const Variant &p_value) {
if (p_value.get_type() == Variant::ARRAY) { if (p_value.get_type() == Variant::ARRAY) {
return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace("\n", " "); return Variant(Array(p_value, 0, StringName(), Variant())).get_construct_string().replace_char('\n', ' ');
} else if (p_value.get_type() == Variant::DICTIONARY) { } else if (p_value.get_type() == Variant::DICTIONARY) {
return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string().replace("\n", " "); return Variant(Dictionary(p_value, 0, StringName(), Variant(), 0, StringName(), Variant())).get_construct_string().replace_char('\n', ' ');
} else { } else {
return p_value.get_construct_string().replace("\n", " "); return p_value.get_construct_string().replace_char('\n', ' ');
} }
} }

View file

@ -146,7 +146,7 @@ Error DirAccess::make_dir_recursive(const String &p_dir) {
full_dir = p_dir; full_dir = p_dir;
} }
full_dir = full_dir.replace("\\", "/"); full_dir = full_dir.replace_char('\\', '/');
String base; String base;

View file

@ -259,7 +259,7 @@ FileAccess::AccessType FileAccess::get_access_type() const {
String FileAccess::fix_path(const String &p_path) const { String FileAccess::fix_path(const String &p_path) const {
// Helper used by file accesses that use a single filesystem. // Helper used by file accesses that use a single filesystem.
String r_path = p_path.replace("\\", "/"); String r_path = p_path.replace_char('\\', '/');
switch (_access_type) { switch (_access_type) {
case ACCESS_RESOURCES: { case ACCESS_RESOURCES: {

View file

@ -548,7 +548,7 @@ String DirAccessPack::get_drive(int p_drive) {
} }
PackedData::PackedDir *DirAccessPack::_find_dir(const String &p_dir) { PackedData::PackedDir *DirAccessPack::_find_dir(const String &p_dir) {
String nd = p_dir.replace("\\", "/"); String nd = p_dir.replace_char('\\', '/');
// Special handling since simplify_path() will forbid it // Special handling since simplify_path() will forbid it
if (p_dir == "..") { if (p_dir == "..") {

View file

@ -2294,7 +2294,7 @@ void Image::initialize_data(const char **p_xpm) {
switch (status) { switch (status) {
case READING_HEADER: { case READING_HEADER: {
String line_str = line_ptr; String line_str = line_ptr;
line_str.replace("\t", " "); line_str.replace_char('\t', ' ');
size_width = line_str.get_slicec(' ', 0).to_int(); size_width = line_str.get_slicec(' ', 0).to_int();
size_height = line_str.get_slicec(' ', 1).to_int(); size_height = line_str.get_slicec(' ', 1).to_int();

View file

@ -155,7 +155,7 @@ void RotatedFileLogger::rotate_file() {
if (FileAccess::exists(base_path)) { if (FileAccess::exists(base_path)) {
if (max_files > 1) { if (max_files > 1) {
String timestamp = Time::get_singleton()->get_datetime_string_from_system().replace(":", "."); String timestamp = Time::get_singleton()->get_datetime_string_from_system().replace_char(':', '.');
String backup_name = base_path.get_basename() + timestamp; String backup_name = base_path.get_basename() + timestamp;
if (!base_path.get_extension().is_empty()) { if (!base_path.get_extension().is_empty()) {
backup_name += "." + base_path.get_extension(); backup_name += "." + base_path.get_extension();

View file

@ -254,7 +254,7 @@ String OS::get_safe_dir_name(const String &p_dir_name, bool p_allow_paths) const
if (p_allow_paths) { if (p_allow_paths) {
// Dir separators are allowed, but disallow ".." to avoid going up the filesystem // Dir separators are allowed, but disallow ".." to avoid going up the filesystem
invalid_chars.push_back(".."); invalid_chars.push_back("..");
safe_dir_name = safe_dir_name.replace("\\", "/").replace("//", "/").strip_edges(); safe_dir_name = safe_dir_name.replace_char('\\', '/').replace("//", "/").strip_edges();
} else { } else {
invalid_chars.push_back("/"); invalid_chars.push_back("/");
invalid_chars.push_back("\\"); invalid_chars.push_back("\\");

View file

@ -135,7 +135,7 @@ TranslationServer::Locale::operator String() const {
TranslationServer::Locale::Locale(const TranslationServer &p_server, const String &p_locale, bool p_add_defaults) { TranslationServer::Locale::Locale(const TranslationServer &p_server, const String &p_locale, bool p_add_defaults) {
// Replaces '-' with '_' for macOS style locales. // Replaces '-' with '_' for macOS style locales.
String univ_locale = p_locale.replace("-", "_"); String univ_locale = p_locale.replace_char('-', '_');
// Extract locale elements. // Extract locale elements.
Vector<String> locale_elements = univ_locale.get_slicec('@', 0).split("_"); Vector<String> locale_elements = univ_locale.get_slicec('@', 0).split("_");

View file

@ -925,7 +925,7 @@ String String::_camelcase_to_underscore() const {
} }
String String::capitalize() const { String String::capitalize() const {
String aux = _camelcase_to_underscore().replace("_", " ").strip_edges(); String aux = _camelcase_to_underscore().replace_char('_', ' ').strip_edges();
String cap; String cap;
for (int i = 0; i < aux.get_slice_count(" "); i++) { for (int i = 0; i < aux.get_slice_count(" "); i++) {
String slice = aux.get_slicec(' ', i); String slice = aux.get_slicec(' ', i);
@ -954,7 +954,7 @@ String String::to_pascal_case() const {
} }
String String::to_snake_case() const { String String::to_snake_case() const {
return _camelcase_to_underscore().replace(" ", "_").strip_edges(); return _camelcase_to_underscore().replace_char(' ', '_').strip_edges();
} }
String String::get_with_code_lines() const { String String::get_with_code_lines() const {
@ -4199,6 +4199,117 @@ String String::replace_first(const char *p_key, const char *p_with) const {
return *this; return *this;
} }
String String::replace_char(char32_t p_key, char32_t p_with) const {
ERR_FAIL_COND_V_MSG(p_with == 0, *this, "`with` must not be the NUL character.");
if (p_key == 0) {
return *this;
}
int len = length();
if (len == 0) {
return *this;
}
int index = 0;
const char32_t *old_ptr = ptr();
for (; index < len; ++index) {
if (old_ptr[index] == p_key) {
break;
}
}
// If no occurrence of `key` was found, return this.
if (index == len) {
return *this;
}
// If we found at least one occurrence of `key`, create new string.
String new_string;
new_string.resize(len + 1);
char32_t *new_ptr = new_string.ptrw();
// Copy part of input before `key`.
memcpy(new_ptr, old_ptr, index * sizeof(char32_t));
new_ptr[index] = p_with;
// Copy or replace rest of input.
for (++index; index < len; ++index) {
if (old_ptr[index] == p_key) {
new_ptr[index] = p_with;
} else {
new_ptr[index] = old_ptr[index];
}
}
new_ptr[index] = _null;
return new_string;
}
template <class T>
static String _replace_chars_common(const String &p_this, const T *p_keys, int p_keys_len, char32_t p_with) {
ERR_FAIL_COND_V_MSG(p_with == 0, p_this, "`with` must not be the NUL character.");
// Delegate if p_keys is a single element.
if (p_keys_len == 1) {
return p_this.replace_char(*p_keys, p_with);
} else if (p_keys_len == 0) {
return p_this;
}
int len = p_this.length();
if (len == 0) {
return p_this;
}
int index = 0;
const char32_t *old_ptr = p_this.ptr();
for (; index < len; ++index) {
if (_contains_char(old_ptr[index], p_keys, p_keys_len)) {
break;
}
}
// If no occurrence of `keys` was found, return this.
if (index == len) {
return p_this;
}
// If we found at least one occurrence of `keys`, create new string.
String new_string;
new_string.resize(len + 1);
char32_t *new_ptr = new_string.ptrw();
// Copy part of input before `key`.
memcpy(new_ptr, old_ptr, index * sizeof(char32_t));
new_ptr[index] = p_with;
// Copy or replace rest of input.
for (++index; index < len; ++index) {
const char32_t old_char = old_ptr[index];
if (_contains_char(old_char, p_keys, p_keys_len)) {
new_ptr[index] = p_with;
} else {
new_ptr[index] = old_char;
}
}
new_ptr[index] = 0;
return new_string;
}
String String::replace_chars(const String &p_keys, char32_t p_with) const {
return _replace_chars_common(*this, p_keys.ptr(), p_keys.length(), p_with);
}
String String::replace_chars(const char *p_keys, char32_t p_with) const {
return _replace_chars_common(*this, p_keys, strlen(p_keys), p_with);
}
String String::replacen(const String &p_key, const String &p_with) const { String String::replacen(const String &p_key, const String &p_with) const {
return _replace_common(*this, p_key, p_with, true); return _replace_common(*this, p_key, p_with, true);
} }
@ -4481,7 +4592,7 @@ String String::simplify_path() const {
} }
} }
s = s.replace("\\", "/"); s = s.replace_char('\\', '/');
while (true) { // in case of using 2 or more slash while (true) { // in case of using 2 or more slash
String compare = s.replace("//", "/"); String compare = s.replace("//", "/");
if (s == compare) { if (s == compare) {
@ -5124,8 +5235,8 @@ bool String::is_valid_float() const {
String String::path_to_file(const String &p_path) const { 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. // Don't get base dir for src, this is expected to be a dir already.
String src = replace("\\", "/"); String src = replace_char('\\', '/');
String dst = p_path.replace("\\", "/").get_base_dir(); String dst = p_path.replace_char('\\', '/').get_base_dir();
String rel = src.path_to(dst); String rel = src.path_to(dst);
if (rel == dst) { // failed if (rel == dst) { // failed
return p_path; return p_path;
@ -5135,8 +5246,8 @@ String String::path_to_file(const String &p_path) const {
} }
String String::path_to(const String &p_path) const { String String::path_to(const String &p_path) const {
String src = replace("\\", "/"); String src = replace_char('\\', '/');
String dst = p_path.replace("\\", "/"); String dst = p_path.replace_char('\\', '/');
if (!src.ends_with("/")) { if (!src.ends_with("/")) {
src += "/"; src += "/";
} }

View file

@ -396,6 +396,9 @@ public:
String replace_first(const char *p_key, const char *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 replace_char(char32_t p_key, char32_t p_with) const;
String replace_chars(const String &p_keys, char32_t p_with) const;
String replace_chars(const char *p_keys, char32_t 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 replacen(const char *p_key, const char *p_with) const;
String repeat(int p_count) const; String repeat(int p_count) const;

View file

@ -1739,6 +1739,8 @@ static void _register_variant_builtin_methods_string() {
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_methodv(replacen, static_cast<String (String::*)(const String &, const String &) const>(&String::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(replace_char, sarray("key", "with"), varray());
bind_string_methodv(replace_chars, static_cast<String (String::*)(const String &, char32_t) const>(&String::replace_chars), sarray("keys", "with"), varray());
bind_string_method(remove_char, sarray("what"), varray()); bind_string_method(remove_char, sarray("what"), varray());
bind_string_methodv(remove_chars, static_cast<String (String::*)(const String &) const>(&String::remove_chars), sarray("chars"), varray()); bind_string_methodv(remove_chars, static_cast<String (String::*)(const String &) const>(&String::remove_chars), sarray("chars"), varray());
bind_string_method(repeat, sarray("count"), varray()); bind_string_method(repeat, sarray("count"), varray());

View file

@ -792,6 +792,22 @@
Replaces all occurrences of [param what] inside the string with the given [param forwhat]. Replaces all occurrences of [param what] inside the string with the given [param forwhat].
</description> </description>
</method> </method>
<method name="replace_char" qualifiers="const">
<return type="String" />
<param index="0" name="key" type="int" />
<param index="1" name="with" type="int" />
<description>
Replaces all occurrences of the Unicode character with code [param key] with the Unicode character with code [param with]. Faster version of [method replace] when the key is only one character long. To get a single character use [code]"X".unicode_at(0)[/code] (note that some strings, like compound letters and emoji, can be made up of multiple unicode codepoints, and will not work with this method, use [method length] to make sure).
</description>
</method>
<method name="replace_chars" qualifiers="const">
<return type="String" />
<param index="0" name="keys" type="String" />
<param index="1" name="with" type="int" />
<description>
Replaces any occurrence of the characters in [param keys] with the Unicode character with code [param with]. See also [method replace_char].
</description>
</method>
<method name="replacen" qualifiers="const"> <method name="replacen" qualifiers="const">
<return type="String" /> <return type="String" />
<param index="0" name="what" type="String" /> <param index="0" name="what" type="String" />

View file

@ -700,6 +700,22 @@
Replaces all occurrences of [param what] inside the string with the given [param forwhat]. Replaces all occurrences of [param what] inside the string with the given [param forwhat].
</description> </description>
</method> </method>
<method name="replace_char" qualifiers="const">
<return type="String" />
<param index="0" name="key" type="int" />
<param index="1" name="with" type="int" />
<description>
Replaces all occurrences of the Unicode character with code [param key] with the Unicode character with code [param with]. Faster version of [method replace] when the key is only one character long. To get a single character use [code]"X".unicode_at(0)[/code] (note that some strings, like compound letters and emoji, can be made up of multiple unicode codepoints, and will not work with this method, use [method length] to make sure).
</description>
</method>
<method name="replace_chars" qualifiers="const">
<return type="String" />
<param index="0" name="keys" type="String" />
<param index="1" name="with" type="int" />
<description>
Replaces any occurrence of the characters in [param keys] with the Unicode character with code [param with]. See also [method replace_char].
</description>
</method>
<method name="replacen" qualifiers="const"> <method name="replacen" qualifiers="const">
<return type="String" /> <return type="String" />
<param index="0" name="what" type="String" /> <param index="0" name="what" type="String" />

View file

@ -151,7 +151,7 @@ int EGLManager::_get_gldisplay_id(void *p_display) {
String EGLManager::shader_cache_dir; String EGLManager::shader_cache_dir;
void EGLManager::_set_cache(const void *p_key, EGLsizeiANDROID p_key_size, const void *p_value, EGLsizeiANDROID p_value_size) { void EGLManager::_set_cache(const void *p_key, EGLsizeiANDROID p_key_size, const void *p_value, EGLsizeiANDROID p_value_size) {
String name = CryptoCore::b64_encode_str((const uint8_t *)p_key, p_key_size).replace("/", "_"); String name = CryptoCore::b64_encode_str((const uint8_t *)p_key, p_key_size).replace_char('/', '_');
String path = shader_cache_dir.path_join(name) + ".cache"; String path = shader_cache_dir.path_join(name) + ".cache";
Error err = OK; Error err = OK;
@ -163,7 +163,7 @@ void EGLManager::_set_cache(const void *p_key, EGLsizeiANDROID p_key_size, const
} }
EGLsizeiANDROID EGLManager::_get_cache(const void *p_key, EGLsizeiANDROID p_key_size, void *p_value, EGLsizeiANDROID p_value_size) { EGLsizeiANDROID EGLManager::_get_cache(const void *p_key, EGLsizeiANDROID p_key_size, void *p_value, EGLsizeiANDROID p_value_size) {
String name = CryptoCore::b64_encode_str((const uint8_t *)p_key, p_key_size).replace("/", "_"); String name = CryptoCore::b64_encode_str((const uint8_t *)p_key, p_key_size).replace_char('/', '_');
String path = shader_cache_dir.path_join(name) + ".cache"; String path = shader_cache_dir.path_join(name) + ".cache";
Error err = OK; Error err = OK;

View file

@ -3062,7 +3062,7 @@ void RenderingDeviceDriverMetal::command_bind_push_constants(CommandBufferID p_c
String RenderingDeviceDriverMetal::_pipeline_get_cache_path() const { String RenderingDeviceDriverMetal::_pipeline_get_cache_path() const {
String path = OS::get_singleton()->get_user_data_dir() + "/metal/pipelines"; String path = OS::get_singleton()->get_user_data_dir() + "/metal/pipelines";
path += "." + context_device.name.validate_filename().replace(" ", "_").to_lower(); path += "." + context_device.name.validate_filename().replace_char(' ', '_').to_lower();
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
path += ".editor"; path += ".editor";
} }

View file

@ -67,7 +67,7 @@ Error FileAccessUnixPipe::open_internal(const String &p_path, int p_mode_flags)
path_src = p_path; path_src = p_path;
ERR_FAIL_COND_V_MSG(fd[0] >= 0 || fd[1] >= 0, ERR_ALREADY_IN_USE, "Pipe is already in use."); ERR_FAIL_COND_V_MSG(fd[0] >= 0 || fd[1] >= 0, ERR_ALREADY_IN_USE, "Pipe is already in use.");
path = String("/tmp/") + p_path.replace("pipe://", "").replace("/", "_"); path = String("/tmp/") + p_path.replace("pipe://", "").replace_char('/', '_');
const CharString path_utf8 = path.utf8(); const CharString path_utf8 = path.utf8();
struct stat st = {}; struct stat st = {};

View file

@ -70,17 +70,17 @@ struct DirAccessWindowsPrivate {
}; };
String DirAccessWindows::fix_path(const String &p_path) const { String DirAccessWindows::fix_path(const String &p_path) const {
String r_path = DirAccess::fix_path(p_path.trim_prefix(R"(\\?\)").replace("\\", "/")); String r_path = DirAccess::fix_path(p_path.trim_prefix(R"(\\?\)").replace_char('\\', '/'));
if (r_path.ends_with(":")) { if (r_path.ends_with(":")) {
r_path += "/"; r_path += "/";
} }
if (r_path.is_relative_path()) { if (r_path.is_relative_path()) {
r_path = current_dir.trim_prefix(R"(\\?\)").replace("\\", "/").path_join(r_path); r_path = current_dir.trim_prefix(R"(\\?\)").replace_char('\\', '/').path_join(r_path);
} else if (r_path == ".") { } else if (r_path == ".") {
r_path = current_dir.trim_prefix(R"(\\?\)").replace("\\", "/"); r_path = current_dir.trim_prefix(R"(\\?\)").replace_char('\\', '/');
} }
r_path = r_path.simplify_path(); r_path = r_path.simplify_path();
r_path = r_path.replace("/", "\\"); r_path = r_path.replace_char('/', '\\');
if (!r_path.is_network_share_path() && !r_path.begins_with(R"(\\?\)")) { if (!r_path.is_network_share_path() && !r_path.begins_with(R"(\\?\)")) {
r_path = R"(\\?\)" + r_path; r_path = R"(\\?\)" + r_path;
} }
@ -167,7 +167,7 @@ Error DirAccessWindows::change_dir(String p_dir) {
str_len = GetCurrentDirectoryW(0, nullptr); str_len = GetCurrentDirectoryW(0, nullptr);
real_current_dir_name.resize(str_len + 1); real_current_dir_name.resize(str_len + 1);
GetCurrentDirectoryW(real_current_dir_name.size(), (LPWSTR)real_current_dir_name.ptrw()); GetCurrentDirectoryW(real_current_dir_name.size(), (LPWSTR)real_current_dir_name.ptrw());
String new_dir = String::utf16((const char16_t *)real_current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/"); String new_dir = String::utf16((const char16_t *)real_current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace_char('\\', '/');
if (!new_dir.begins_with(base)) { if (!new_dir.begins_with(base)) {
worked = false; worked = false;
} }
@ -215,7 +215,7 @@ Error DirAccessWindows::make_dir(String p_dir) {
} }
String DirAccessWindows::get_current_dir(bool p_include_drive) const { String DirAccessWindows::get_current_dir(bool p_include_drive) const {
String cdir = current_dir.trim_prefix(R"(\\?\)").replace("\\", "/"); String cdir = current_dir.trim_prefix(R"(\\?\)").replace_char('\\', '/');
String base = _get_root_path(); String base = _get_root_path();
if (!base.is_empty()) { if (!base.is_empty()) {
String bd = cdir.replace_first(base, ""); String bd = cdir.replace_first(base, "");
@ -451,7 +451,7 @@ String DirAccessWindows::read_link(String p_file) {
GetFinalPathNameByHandleW(hfile, (LPWSTR)cs.ptrw(), ret, VOLUME_NAME_DOS | FILE_NAME_NORMALIZED); GetFinalPathNameByHandleW(hfile, (LPWSTR)cs.ptrw(), ret, VOLUME_NAME_DOS | FILE_NAME_NORMALIZED);
CloseHandle(hfile); CloseHandle(hfile);
return String::utf16((const char16_t *)cs.ptr(), ret).trim_prefix(R"(\\?\)").replace("\\", "/"); return String::utf16((const char16_t *)cs.ptr(), ret).trim_prefix(R"(\\?\)").replace_char('\\', '/');
} }
Error DirAccessWindows::create_link(String p_source, String p_target) { Error DirAccessWindows::create_link(String p_source, String p_target) {

View file

@ -87,10 +87,10 @@ String FileAccessWindows::fix_path(const String &p_path) const {
size_t str_len = GetCurrentDirectoryW(0, nullptr); size_t str_len = GetCurrentDirectoryW(0, nullptr);
current_dir_name.resize(str_len + 1); current_dir_name.resize(str_len + 1);
GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw()); GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
r_path = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/").path_join(r_path); r_path = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace_char('\\', '/').path_join(r_path);
} }
r_path = r_path.simplify_path(); r_path = r_path.simplify_path();
r_path = r_path.replace("/", "\\"); r_path = r_path.replace_char('/', '\\');
if (!r_path.is_network_share_path() && !r_path.begins_with(R"(\\?\)")) { if (!r_path.is_network_share_path() && !r_path.begins_with(R"(\\?\)")) {
r_path = R"(\\?\)" + r_path; r_path = R"(\\?\)" + r_path;
} }
@ -282,7 +282,7 @@ String FileAccessWindows::get_path() const {
} }
String FileAccessWindows::get_path_absolute() const { String FileAccessWindows::get_path_absolute() const {
return path.trim_prefix(R"(\\?\)").replace("\\", "/"); return path.trim_prefix(R"(\\?\)").replace_char('\\', '/');
} }
bool FileAccessWindows::is_open() const { bool FileAccessWindows::is_open() const {

View file

@ -60,7 +60,7 @@ Error FileAccessWindowsPipe::open_internal(const String &p_path, int p_mode_flag
path_src = p_path; path_src = p_path;
ERR_FAIL_COND_V_MSG(fd[0] != nullptr || fd[1] != nullptr, ERR_ALREADY_IN_USE, "Pipe is already in use."); ERR_FAIL_COND_V_MSG(fd[0] != nullptr || fd[1] != nullptr, ERR_ALREADY_IN_USE, "Pipe is already in use.");
path = String("\\\\.\\pipe\\LOCAL\\") + p_path.replace("pipe://", "").replace("/", "_"); path = String("\\\\.\\pipe\\LOCAL\\") + p_path.replace("pipe://", "").replace_char('/', '_');
HANDLE h = CreateFileW((LPCWSTR)path.utf16().get_data(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); HANDLE h = CreateFileW((LPCWSTR)path.utf16().get_data(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (h == INVALID_HANDLE_VALUE) { if (h == INVALID_HANDLE_VALUE) {

View file

@ -356,7 +356,7 @@ Dictionary DebugAdapterParser::req_setBreakpoints(const Dictionary &p_params) co
// If path contains \, it's a Windows path, so we need to convert it to /, and make the drive letter uppercase // If path contains \, it's a Windows path, so we need to convert it to /, and make the drive letter uppercase
if (source.path.contains_char('\\')) { if (source.path.contains_char('\\')) {
source.path = source.path.replace("\\", "/"); source.path = source.path.replace_char('\\', '/');
source.path = source.path.substr(0, 1).to_upper() + source.path.substr(1); source.path = source.path.substr(0, 1).to_upper() + source.path.substr(1);
} }

View file

@ -48,7 +48,7 @@ private:
// If path contains \, it's a Windows path, so we need to convert it to /, and check as case-insensitive. // If path contains \, it's a Windows path, so we need to convert it to /, and check as case-insensitive.
if (p_path.contains_char('\\')) { if (p_path.contains_char('\\')) {
String project_path = ProjectSettings::get_singleton()->get_resource_path(); String project_path = ProjectSettings::get_singleton()->get_resource_path();
String path = p_path.replace("\\", "/"); String path = p_path.replace_char('\\', '/');
return path.containsn(project_path); return path.containsn(project_path);
} }
return p_path.begins_with(ProjectSettings::get_singleton()->get_resource_path()); return p_path.begins_with(ProjectSettings::get_singleton()->get_resource_path());

View file

@ -940,7 +940,7 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
DocData::ConstantDoc constant; DocData::ConstantDoc constant;
constant.name = E; constant.name = E;
Variant value = Variant::get_constant_value(Variant::Type(i), E); Variant value = Variant::get_constant_value(Variant::Type(i), E);
constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string().replace("\n", " "); constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string().replace_char('\n', ' ');
constant.is_value_valid = true; constant.is_value_valid = true;
constant.type = Variant::get_type_name(value.get_type()); constant.type = Variant::get_type_name(value.get_type());
c.constants.push_back(constant); c.constants.push_back(constant);

View file

@ -1867,7 +1867,7 @@ bool EditorFileSystem::_find_file(const String &p_file, EditorFileSystemDirector
return false; return false;
} }
f = f.substr(6); f = f.substr(6);
f = f.replace("\\", "/"); f = f.replace_char('\\', '/');
Vector<String> path = f.split("/"); Vector<String> path = f.split("/");
@ -1993,7 +1993,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p
} }
f = f.substr(6); f = f.substr(6);
f = f.replace("\\", "/"); f = f.replace_char('\\', '/');
if (f.is_empty()) { if (f.is_empty()) {
return filesystem; return filesystem;
} }

View file

@ -103,7 +103,8 @@ const Vector<String> classes_with_csharp_differences = {
}; };
#endif #endif
static const String nbsp = String::chr(160); static const char32_t nbsp_chr = 160;
static const String nbsp = String::chr(nbsp_chr);
static const String nbsp_equal_nbsp = nbsp + "=" + nbsp; static const String nbsp_equal_nbsp = nbsp + "=" + nbsp;
static const String colon_nbsp = ":" + nbsp; static const String colon_nbsp = ":" + nbsp;
@ -121,7 +122,7 @@ const Vector<String> packed_array_types = {
}; };
static String _replace_nbsp_with_space(const String &p_string) { static String _replace_nbsp_with_space(const String &p_string) {
return p_string.replace(nbsp, " "); return p_string.replace_char(nbsp_chr, ' ');
} }
static String _fix_constant(const String &p_constant) { static String _fix_constant(const String &p_constant) {

View file

@ -3374,11 +3374,11 @@ String EditorNode::adjust_scene_name_casing(const String &p_root_name) {
// Use casing of the root node. // Use casing of the root node.
break; break;
case SCENE_NAME_CASING_PASCAL_CASE: case SCENE_NAME_CASING_PASCAL_CASE:
return p_root_name.replace("-", "_").to_pascal_case(); return p_root_name.replace_char('-', '_').to_pascal_case();
case SCENE_NAME_CASING_SNAKE_CASE: case SCENE_NAME_CASING_SNAKE_CASE:
return p_root_name.replace("-", "_").to_snake_case(); return p_root_name.replace_char('-', '_').to_snake_case();
case SCENE_NAME_CASING_KEBAB_CASE: case SCENE_NAME_CASING_KEBAB_CASE:
return p_root_name.to_snake_case().replace("_", "-"); return p_root_name.to_snake_case().replace_char('_', '-');
} }
return p_root_name; return p_root_name;
} }
@ -3395,11 +3395,11 @@ String EditorNode::adjust_script_name_casing(const String &p_file_name, ScriptLa
// Script language has no preference, so do not adjust. // Script language has no preference, so do not adjust.
break; break;
case ScriptLanguage::SCRIPT_NAME_CASING_PASCAL_CASE: case ScriptLanguage::SCRIPT_NAME_CASING_PASCAL_CASE:
return p_file_name.replace("-", "_").to_pascal_case(); return p_file_name.replace_char('-', '_').to_pascal_case();
case ScriptLanguage::SCRIPT_NAME_CASING_SNAKE_CASE: case ScriptLanguage::SCRIPT_NAME_CASING_SNAKE_CASE:
return p_file_name.replace("-", "_").to_snake_case(); return p_file_name.replace_char('-', '_').to_snake_case();
case ScriptLanguage::SCRIPT_NAME_CASING_KEBAB_CASE: case ScriptLanguage::SCRIPT_NAME_CASING_KEBAB_CASE:
return p_file_name.to_snake_case().replace("_", "-"); return p_file_name.to_snake_case().replace_char('_', '-');
} }
return p_file_name; return p_file_name;
} }

View file

@ -384,7 +384,7 @@ void EditorResourcePreview::_write_preview_cache(Ref<FileAccess> p_file, int p_t
p_file->store_line(itos(p_has_small_texture)); p_file->store_line(itos(p_has_small_texture));
p_file->store_line(itos(p_modified_time)); p_file->store_line(itos(p_modified_time));
p_file->store_line(p_hash); p_file->store_line(p_hash);
p_file->store_line(VariantUtilityFunctions::var_to_str(p_metadata).replace("\n", " ")); p_file->store_line(VariantUtilityFunctions::var_to_str(p_metadata).replace_char('\n', ' '));
p_file->store_line(itos(CURRENT_METADATA_VERSION)); p_file->store_line(itos(CURRENT_METADATA_VERSION));
} }

View file

@ -501,7 +501,7 @@ void EditorExportPlatform::_export_find_dependencies(const String &p_path, HashS
void EditorExportPlatform::_edit_files_with_filter(Ref<DirAccess> &da, const Vector<String> &p_filters, HashSet<String> &r_list, bool exclude) { void EditorExportPlatform::_edit_files_with_filter(Ref<DirAccess> &da, const Vector<String> &p_filters, HashSet<String> &r_list, bool exclude) {
da->list_dir_begin(); da->list_dir_begin();
String cur_dir = da->get_current_dir().replace("\\", "/"); String cur_dir = da->get_current_dir().replace_char('\\', '/');
if (!cur_dir.ends_with("/")) { if (!cur_dir.ends_with("/")) {
cur_dir += "/"; cur_dir += "/";
} }

View file

@ -73,7 +73,7 @@ void ProjectExportTextureFormatError::_notification(int p_what) {
} }
void ProjectExportTextureFormatError::show_for_texture_format(const String &p_friendly_name, const String &p_setting_identifier) { void ProjectExportTextureFormatError::show_for_texture_format(const String &p_friendly_name, const String &p_setting_identifier) {
texture_format_error_label->set_text(vformat(TTR("Target platform requires '%s' texture compression. Enable 'Import %s' to fix."), p_friendly_name, p_friendly_name.replace("/", " "))); texture_format_error_label->set_text(vformat(TTR("Target platform requires '%s' texture compression. Enable 'Import %s' to fix."), p_friendly_name, p_friendly_name.replace_char('/', ' ')));
setting_identifier = p_setting_identifier; setting_identifier = p_setting_identifier;
show(); show();
} }

View file

@ -42,9 +42,9 @@ String ProjectZIPPacker::get_project_zip_safe_name() {
// In the project name, all invalid characters become an empty string so that a name // In the project name, all invalid characters become an empty string so that a name
// like "Platformer 2: Godette's Revenge" becomes "platformer_2-_godette-s_revenge". // like "Platformer 2: Godette's Revenge" becomes "platformer_2-_godette-s_revenge".
const String project_name = GLOBAL_GET("application/config/name"); const String project_name = GLOBAL_GET("application/config/name");
const String project_name_safe = project_name.to_lower().replace(" ", "_"); const String project_name_safe = project_name.to_lower().replace_char(' ', '_');
const String datetime_safe = const String datetime_safe =
Time::get_singleton()->get_datetime_string_from_system(false, true).replace(" ", "_"); Time::get_singleton()->get_datetime_string_from_system(false, true).replace_char(' ', '_');
const String output_name = OS::get_singleton()->get_safe_dir_name(vformat("%s_%s.zip", project_name_safe, datetime_safe)); const String output_name = OS::get_singleton()->get_safe_dir_name(vformat("%s_%s.zip", project_name_safe, datetime_safe));
return output_name; return output_name;
} }

View file

@ -594,7 +594,7 @@ void EditorFileDialog::_action_pressed() {
} else if (mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_DIR) { } else if (mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_DIR) {
String path = dir_access->get_current_dir(); String path = dir_access->get_current_dir();
path = path.replace("\\", "/"); path = path.replace_char('\\', '/');
for (int i = 0; i < item_list->get_item_count(); i++) { for (int i = 0; i < item_list->get_item_count(); i++) {
if (item_list->is_selected(i)) { if (item_list->is_selected(i)) {

View file

@ -568,8 +568,8 @@ void EditorSpinSlider::_evaluate_input_text() {
expr.instantiate(); expr.instantiate();
// Convert commas ',' to dots '.' for French/German etc. keyboard layouts. // Convert commas ',' to dots '.' for French/German etc. keyboard layouts.
String text = value_input->get_text().replace(",", "."); String text = value_input->get_text().replace_char(',', '.');
text = text.replace(";", ","); text = text.replace_char(';', ',');
text = TS->parse_number(text); text = TS->parse_number(text);
Error err = expr->parse(text); Error err = expr->parse(text);

View file

@ -119,7 +119,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
//normal //normal
ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT); ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT);
String p = l.replace("map_Kd", "").replace("\\", "/").strip_edges(); String p = l.replace("map_Kd", "").replace_char('\\', '/').strip_edges();
String path; String path;
if (p.is_absolute_path()) { if (p.is_absolute_path()) {
path = p; path = p;
@ -139,7 +139,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
//normal //normal
ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT); ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT);
String p = l.replace("map_Ks", "").replace("\\", "/").strip_edges(); String p = l.replace("map_Ks", "").replace_char('\\', '/').strip_edges();
String path; String path;
if (p.is_absolute_path()) { if (p.is_absolute_path()) {
path = p; path = p;
@ -159,7 +159,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
//normal //normal
ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT); ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT);
String p = l.replace("map_Ns", "").replace("\\", "/").strip_edges(); String p = l.replace("map_Ns", "").replace_char('\\', '/').strip_edges();
String path; String path;
if (p.is_absolute_path()) { if (p.is_absolute_path()) {
path = p; path = p;
@ -178,7 +178,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
//normal //normal
ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT); ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT);
String p = l.replace("map_bump", "").replace("\\", "/").strip_edges(); String p = l.replace("map_bump", "").replace_char('\\', '/').strip_edges();
String path = base_path.path_join(p); String path = base_path.path_join(p);
Ref<Texture2D> texture = ResourceLoader::load(path); Ref<Texture2D> texture = ResourceLoader::load(path);

View file

@ -478,7 +478,7 @@ void EditorPropertyOTVariation::update_property() {
String name = TS->tag_to_name(name_tag); String name = TS->tag_to_name(name_tag);
String name_cap; String name_cap;
{ {
String aux = name.replace("_", " ").strip_edges(); String aux = name.replace_char('_', ' ').strip_edges();
for (int j = 0; j < aux.get_slice_count(" "); j++) { for (int j = 0; j < aux.get_slice_count(" "); j++) {
String slice = aux.get_slicec(' ', j); String slice = aux.get_slicec(' ', j);
if (slice.length() > 0) { if (slice.length() > 0) {

View file

@ -144,7 +144,7 @@ void PluginConfigDialog::_on_required_text_changed() {
} }
String PluginConfigDialog::_get_subfolder() { String PluginConfigDialog::_get_subfolder() {
return subfolder_edit->get_text().is_empty() ? name_edit->get_text().replace(" ", "_").to_lower() : subfolder_edit->get_text(); return subfolder_edit->get_text().is_empty() ? name_edit->get_text().replace_char(' ', '_').to_lower() : subfolder_edit->get_text();
} }
String PluginConfigDialog::_to_absolute_plugin_path(const String &p_plugin_name) { String PluginConfigDialog::_to_absolute_plugin_path(const String &p_plugin_name) {

View file

@ -1104,7 +1104,7 @@ void SpriteFramesEditor::_animation_name_edited() {
new_name = "new_animation"; new_name = "new_animation";
} }
new_name = new_name.replace("/", "_").replace(",", " "); new_name = new_name.replace_char('/', '_').replace_char(',', ' ');
String name = new_name; String name = new_name;
int counter = 0; int counter = 0;

View file

@ -277,7 +277,7 @@ void ProjectDialog::_update_target_auto_dir() {
case 0: // No convention case 0: // No convention
break; break;
case 1: // kebab-case case 1: // kebab-case
new_auto_dir = new_auto_dir.to_lower().replace(" ", "-"); new_auto_dir = new_auto_dir.to_lower().replace_char(' ', '-');
break; break;
case 2: // snake_case case 2: // snake_case
new_auto_dir = new_auto_dir.to_snake_case(); new_auto_dir = new_auto_dir.to_snake_case();

View file

@ -81,7 +81,7 @@ void PropertySelector::_update_search() {
TreeItem *root = search_options->create_item(); TreeItem *root = search_options->create_item();
// Allow using spaces in place of underscores in the search string (makes the search more fault-tolerant). // Allow using spaces in place of underscores in the search string (makes the search more fault-tolerant).
const String search_text = search_box->get_text().replace(" ", "_"); const String search_text = search_box->get_text().replace_char(' ', '_');
if (properties) { if (properties) {
List<PropertyInfo> props; List<PropertyInfo> props;

View file

@ -4425,7 +4425,7 @@ int Main::start() {
String local_game_path; String local_game_path;
if (!game_path.is_empty() && !project_manager) { if (!game_path.is_empty() && !project_manager) {
local_game_path = game_path.replace("\\", "/"); local_game_path = game_path.replace_char('\\', '/');
if (!local_game_path.begins_with("res://")) { if (!local_game_path.begins_with("res://")) {
bool absolute = bool absolute =

View file

@ -177,7 +177,7 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {
#ifndef WINDOWS_ENABLED #ifndef WINDOWS_ENABLED
is_same_workspace = root.to_lower() == workspace->root.to_lower(); is_same_workspace = root.to_lower() == workspace->root.to_lower();
#else #else
is_same_workspace = root.replace("\\", "/").to_lower() == workspace->root.to_lower(); is_same_workspace = root.replace_char('\\', '/').to_lower() == workspace->root.to_lower();
#endif #endif
if (root_uri.length() && is_same_workspace) { if (root_uri.length() && is_same_workspace) {

View file

@ -1939,8 +1939,7 @@ static String marked_documentation(const String &p_bbcode) {
line = line.replace("[signal ", "`"); line = line.replace("[signal ", "`");
line = line.replace("[enum ", "`"); line = line.replace("[enum ", "`");
line = line.replace("[constant ", "`"); line = line.replace("[constant ", "`");
line = line.replace("[", "`"); line = line.replace_chars("[]", '`');
line = line.replace("]", "`");
} }
if (!in_code_block && i < lines.size() - 1) { if (!in_code_block && i < lines.size() - 1) {

View file

@ -478,7 +478,7 @@ void GDScriptTest::error_handler(void *p_this, const char *p_function, const cha
if (include_source_info) { if (include_source_info) {
header += vformat(" at %s:%d on %s()", header += vformat(" at %s:%d on %s()",
String::utf8(p_file).trim_prefix(self->base_dir).replace("\\", "/"), String::utf8(p_file).trim_prefix(self->base_dir).replace_char('\\', '/'),
p_line, p_line,
String::utf8(p_function)); String::utf8(p_function));
} }

View file

@ -531,8 +531,7 @@ String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> p_state, const St
String GLTFDocument::_sanitize_bone_name(const String &p_name) { String GLTFDocument::_sanitize_bone_name(const String &p_name) {
String bone_name = p_name; String bone_name = p_name;
bone_name = bone_name.replace(":", "_"); bone_name = bone_name.replace_chars(":/", '_');
bone_name = bone_name.replace("/", "_");
return bone_name; return bone_name;
} }
@ -813,7 +812,7 @@ Error GLTFDocument::_parse_buffers(Ref<GLTFState> p_state, const String &p_base_
} else { // Relative path to an external image file. } else { // Relative path to an external image file.
ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER);
uri = uri.uri_file_decode(); uri = uri.uri_file_decode();
uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows. uri = p_base_path.path_join(uri).replace_char('\\', '/'); // Fix for Windows.
ERR_FAIL_COND_V_MSG(!FileAccess::exists(uri), ERR_FILE_NOT_FOUND, "glTF: Binary file not found: " + uri); ERR_FAIL_COND_V_MSG(!FileAccess::exists(uri), ERR_FILE_NOT_FOUND, "glTF: Binary file not found: " + uri);
buffer_data = FileAccess::get_file_as_bytes(uri); buffer_data = FileAccess::get_file_as_bytes(uri);
ERR_FAIL_COND_V_MSG(buffer_data.is_empty(), ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri); ERR_FAIL_COND_V_MSG(buffer_data.is_empty(), ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri);
@ -4135,7 +4134,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
} else { // Relative path to an external image file. } else { // Relative path to an external image file.
ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER);
uri = uri.uri_file_decode(); uri = uri.uri_file_decode();
uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows. uri = p_base_path.path_join(uri).replace_char('\\', '/'); // Fix for Windows.
resource_uri = uri.simplify_path(); resource_uri = uri.simplify_path();
// ResourceLoader will rely on the file extension to use the relevant loader. // ResourceLoader will rely on the file extension to use the relevant loader.
// The spec says that if mimeType is defined, it should take precedence (e.g. // The spec says that if mimeType is defined, it should take precedence (e.g.

View file

@ -810,7 +810,6 @@ Error SkinTool::_asset_parse_skins(
String SkinTool::_sanitize_bone_name(const String &p_name) { String SkinTool::_sanitize_bone_name(const String &p_name) {
String bone_name = p_name; String bone_name = p_name;
bone_name = bone_name.replace(":", "_"); bone_name = bone_name.replace_chars(":/", '_');
bone_name = bone_name.replace("/", "_");
return bone_name; return bone_name;
} }

View file

@ -123,9 +123,9 @@ void AudioStreamInteractive::set_clip_stream(int p_clip, const Ref<AudioStream>
if (clips[p_clip].name == StringName() && p_stream.is_valid()) { if (clips[p_clip].name == StringName() && p_stream.is_valid()) {
String n; String n;
if (!clips[p_clip].stream->get_name().is_empty()) { if (!clips[p_clip].stream->get_name().is_empty()) {
n = clips[p_clip].stream->get_name().replace(",", " "); n = clips[p_clip].stream->get_name().replace_char(',', ' ');
} else if (clips[p_clip].stream->get_path().is_resource_file()) { } else if (clips[p_clip].stream->get_path().is_resource_file()) {
n = clips[p_clip].stream->get_path().get_file().get_basename().replace(",", " "); n = clips[p_clip].stream->get_path().get_file().get_basename().replace_char(',', ' ');
n = n.capitalize(); n = n.capitalize();
} }
@ -395,13 +395,13 @@ String AudioStreamInteractive::_get_streams_hint() const {
if (i > 0) { if (i > 0) {
stream_name_cache += ","; stream_name_cache += ",";
} }
String n = String(clips[i].name).replace(",", " "); String n = String(clips[i].name).replace_char(',', ' ');
if (n == "" && clips[i].stream.is_valid()) { if (n == "" && clips[i].stream.is_valid()) {
if (!clips[i].stream->get_name().is_empty()) { if (!clips[i].stream->get_name().is_empty()) {
n = clips[i].stream->get_name().replace(",", " "); n = clips[i].stream->get_name().replace_char(',', ' ');
} else if (clips[i].stream->get_path().is_resource_file()) { } else if (clips[i].stream->get_path().is_resource_file()) {
n = clips[i].stream->get_path().get_file().replace(",", " "); n = clips[i].stream->get_path().get_file().replace_char(',', ' ');
} }
} }

View file

@ -362,7 +362,7 @@ Ref<Script> CSharpLanguage::make_template(const String &p_template, const String
Ref<CSharpScript> scr; Ref<CSharpScript> scr;
scr.instantiate(); scr.instantiate();
String class_name_no_spaces = p_class_name.replace(" ", "_"); String class_name_no_spaces = p_class_name.replace_char(' ', '_');
String base_class_name = get_base_class_name(p_base_class_name, class_name_no_spaces); String base_class_name = get_base_class_name(p_base_class_name, class_name_no_spaces);
String processed_template = p_template; String processed_template = p_template;
processed_template = processed_template.replace("_BINDINGS_NAMESPACE_", BINDINGS_NAMESPACE) processed_template = processed_template.replace("_BINDINGS_NAMESPACE_", BINDINGS_NAMESPACE)

View file

@ -1905,7 +1905,7 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
" <ItemGroup>\n"); " <ItemGroup>\n");
for (int i = 0; i < compile_items.size(); i++) { for (int i = 0; i < compile_items.size(); i++) {
String include = Path::relative_to(compile_items[i], p_proj_dir).replace("/", "\\"); String include = Path::relative_to(compile_items[i], p_proj_dir).replace_char('/', '\\');
includes_props_content.append(" <Compile Include=\"" + include + "\" />\n"); includes_props_content.append(" <Compile Include=\"" + include + "\" />\n");
} }
@ -2065,7 +2065,7 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
" <ItemGroup>\n"); " <ItemGroup>\n");
for (int i = 0; i < compile_items.size(); i++) { for (int i = 0; i < compile_items.size(); i++) {
String include = Path::relative_to(compile_items[i], p_proj_dir).replace("/", "\\"); String include = Path::relative_to(compile_items[i], p_proj_dir).replace_char('/', '\\');
includes_props_content.append(" <Compile Include=\"" + include + "\" />\n"); includes_props_content.append(" <Compile Include=\"" + include + "\" />\n");
} }

View file

@ -262,7 +262,7 @@ bool get_dotnet_self_registered_dir(String &r_dotnet_root) {
return false; return false;
} }
r_dotnet_root = String::utf16((const char16_t *)buffer.ptr()).replace("\\", "/"); r_dotnet_root = String::utf16((const char16_t *)buffer.ptr()).replace_char('\\', '/');
RegCloseKey(hkey); RegCloseKey(hkey);
return true; return true;
#else #else

View file

@ -1714,7 +1714,7 @@ void EditorExportPlatformAndroid::_fix_resources(const Ref<EditorExportPreset> &
str = get_project_name(p_preset, package_name); str = get_project_name(p_preset, package_name);
} else { } else {
String lang = str.substr(str.rfind_char('-') + 1).replace("-", "_"); String lang = str.substr(str.rfind_char('-') + 1).replace_char('-', '_');
if (appnames.has(lang)) { if (appnames.has(lang)) {
str = appnames[lang]; str = appnames[lang];
} else { } else {

View file

@ -1002,7 +1002,7 @@ bool JavaClassWrapper::_get_type_sig(JNIEnv *env, jobject obj, uint32_t &sig, St
strsig += "Ljava/lang/Double;"; strsig += "Ljava/lang/Double;";
} else { } else {
//a class likely //a class likely
strsig += "L" + str_type.replace(".", "/") + ";"; strsig += "L" + str_type.replace_char('.', '/') + ";";
t |= JavaClass::ARG_TYPE_CLASS; t |= JavaClass::ARG_TYPE_CLASS;
} }
@ -1462,7 +1462,7 @@ bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &va
} }
Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_private_methods_access) { Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_private_methods_access) {
String class_name_dots = p_class.replace("/", "."); String class_name_dots = p_class.replace_char('/', '.');
if (class_cache.has(class_name_dots)) { if (class_cache.has(class_name_dots)) {
return class_cache[class_name_dots]; return class_cache[class_name_dots];
} }
@ -1470,7 +1470,7 @@ Ref<JavaClass> JavaClassWrapper::_wrap(const String &p_class, bool p_allow_priva
JNIEnv *env = get_jni_env(); JNIEnv *env = get_jni_env();
ERR_FAIL_NULL_V(env, Ref<JavaClass>()); ERR_FAIL_NULL_V(env, Ref<JavaClass>());
jclass bclass = env->FindClass(class_name_dots.replace(".", "/").utf8().get_data()); jclass bclass = env->FindClass(class_name_dots.replace_char('.', '/').utf8().get_data());
ERR_FAIL_NULL_V_MSG(bclass, Ref<JavaClass>(), vformat("Java class '%s' not found.", p_class)); ERR_FAIL_NULL_V_MSG(bclass, Ref<JavaClass>(), vformat("Java class '%s' not found.", p_class));
jobjectArray constructors = (jobjectArray)env->CallObjectMethod(bclass, Class_getDeclaredConstructors); jobjectArray constructors = (jobjectArray)env->CallObjectMethod(bclass, Class_getDeclaredConstructors);

View file

@ -393,11 +393,11 @@ String OS_IOS::get_locale() const {
NSString *preferredLanguage = [NSLocale preferredLanguages].firstObject; NSString *preferredLanguage = [NSLocale preferredLanguages].firstObject;
if (preferredLanguage) { if (preferredLanguage) {
return String::utf8([preferredLanguage UTF8String]).replace("-", "_"); return String::utf8([preferredLanguage UTF8String]).replace_char('-', '_');
} }
NSString *localeIdentifier = [[NSLocale currentLocale] localeIdentifier]; NSString *localeIdentifier = [[NSLocale currentLocale] localeIdentifier];
return String::utf8([localeIdentifier UTF8String]).replace("-", "_"); return String::utf8([localeIdentifier UTF8String]).replace_char('-', '_');
} }
String OS_IOS::get_unique_id() const { String OS_IOS::get_unique_id() const {

View file

@ -526,7 +526,7 @@ bool FreeDesktopPortalDesktop::color_picker(const String &p_xid, const Callable
String dbus_unique_name = String::utf8(dbus_bus_get_unique_name(monitor_connection)); String dbus_unique_name = String::utf8(dbus_bus_get_unique_name(monitor_connection));
String token = String::hex_encode_buffer(uuid, 64); String token = String::hex_encode_buffer(uuid, 64);
String path = vformat("/org/freedesktop/portal/desktop/request/%s/%s", dbus_unique_name.replace(".", "_").replace(":", ""), token); String path = vformat("/org/freedesktop/portal/desktop/request/%s/%s", dbus_unique_name.replace_char('.', '_').remove_char(':'), token);
cd.path = path; cd.path = path;
cd.filter = vformat("type='signal',sender='org.freedesktop.portal.Desktop',path='%s',interface='org.freedesktop.portal.Request',member='Response',destination='%s'", path, dbus_unique_name); cd.filter = vformat("type='signal',sender='org.freedesktop.portal.Desktop',path='%s',interface='org.freedesktop.portal.Request',member='Response',destination='%s'", path, dbus_unique_name);
@ -717,7 +717,7 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
String dbus_unique_name = String::utf8(dbus_bus_get_unique_name(monitor_connection)); String dbus_unique_name = String::utf8(dbus_bus_get_unique_name(monitor_connection));
String token = String::hex_encode_buffer(uuid, 64); String token = String::hex_encode_buffer(uuid, 64);
String path = vformat("/org/freedesktop/portal/desktop/request/%s/%s", dbus_unique_name.replace(".", "_").remove_char(':'), token); String path = vformat("/org/freedesktop/portal/desktop/request/%s/%s", dbus_unique_name.replace_char('.', '_').remove_char(':'), token);
fd.path = path; fd.path = path;
fd.filter = vformat("type='signal',sender='org.freedesktop.portal.Desktop',path='%s',interface='org.freedesktop.portal.Request',member='Response',destination='%s'", path, dbus_unique_name); fd.filter = vformat("type='signal',sender='org.freedesktop.portal.Desktop',path='%s',interface='org.freedesktop.portal.Request',member='Response',destination='%s'", path, dbus_unique_name);

View file

@ -431,7 +431,7 @@ Error OS_MacOS::shell_open(const String &p_uri) {
String OS_MacOS::get_locale() const { String OS_MacOS::get_locale() const {
NSString *locale_code = [[NSLocale preferredLanguages] objectAtIndex:0]; NSString *locale_code = [[NSLocale preferredLanguages] objectAtIndex:0];
return String([locale_code UTF8String]).replace("-", "_"); return String([locale_code UTF8String]).replace_char('-', '_');
} }
Vector<String> OS_MacOS::get_system_fonts() const { Vector<String> OS_MacOS::get_system_fonts() const {

View file

@ -184,7 +184,7 @@ void OS_Web::vibrate_handheld(int p_duration_ms, float p_amplitude) {
String OS_Web::get_user_data_dir(const String &p_user_dir) const { String OS_Web::get_user_data_dir(const String &p_user_dir) const {
String userfs = "/userfs"; String userfs = "/userfs";
return userfs.path_join(p_user_dir).replace("\\", "/"); return userfs.path_join(p_user_dir).replace_char('\\', '/');
} }
String OS_Web::get_cache_path() const { String OS_Web::get_cache_path() const {

View file

@ -172,7 +172,7 @@ extern void CrashHandlerException(int signal) {
if (FileAccess::exists(_execpath + ".debugsymbols")) { if (FileAccess::exists(_execpath + ".debugsymbols")) {
_execpath = _execpath + ".debugsymbols"; _execpath = _execpath + ".debugsymbols";
} }
_execpath = _execpath.replace("/", "\\"); _execpath = _execpath.replace_char('/', '\\');
CharString cs = _execpath.utf8(); // Note: should remain in scope during backtrace_simple call. CharString cs = _execpath.utf8(); // Note: should remain in scope during backtrace_simple call.
data.state = backtrace_create_state(cs.get_data(), 0, &error_callback, reinterpret_cast<void *>(&data)); data.state = backtrace_create_state(cs.get_data(), 0, &error_callback, reinterpret_cast<void *>(&data));

View file

@ -385,7 +385,7 @@ public:
if (!lpw_path) { if (!lpw_path) {
return S_FALSE; return S_FALSE;
} }
String path = String::utf16((const char16_t *)lpw_path).replace("\\", "/").trim_prefix(R"(\\?\)").simplify_path(); String path = String::utf16((const char16_t *)lpw_path).replace_char('\\', '/').trim_prefix(R"(\\?\)").simplify_path();
if (!path.begins_with(root.simplify_path())) { if (!path.begins_with(root.simplify_path())) {
return S_FALSE; return S_FALSE;
} }
@ -618,13 +618,13 @@ void DisplayServerWindows::_thread_fd_monitor(void *p_ud) {
current_dir_name.resize(str_len + 1); current_dir_name.resize(str_len + 1);
GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw()); GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
if (dir == ".") { if (dir == ".") {
dir = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/"); dir = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace_char('\\', '/');
} else { } else {
dir = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/").path_join(dir); dir = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace_char('\\', '/').path_join(dir);
} }
} }
dir = dir.simplify_path(); dir = dir.simplify_path();
dir = dir.trim_prefix(R"(\\?\)").replace("/", "\\"); dir = dir.trim_prefix(R"(\\?\)").replace_char('/', '\\');
IShellItem *shellitem = nullptr; IShellItem *shellitem = nullptr;
hr = SHCreateItemFromParsingName((LPCWSTR)dir.utf16().ptr(), nullptr, IID_IShellItem, (void **)&shellitem); hr = SHCreateItemFromParsingName((LPCWSTR)dir.utf16().ptr(), nullptr, IID_IShellItem, (void **)&shellitem);
@ -667,7 +667,7 @@ void DisplayServerWindows::_thread_fd_monitor(void *p_ud) {
PWSTR file_path = nullptr; PWSTR file_path = nullptr;
hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path); hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
file_names.push_back(String::utf16((const char16_t *)file_path).replace("\\", "/").trim_prefix(R"(\\?\)")); file_names.push_back(String::utf16((const char16_t *)file_path).replace_char('\\', '/').trim_prefix(R"(\\?\)"));
CoTaskMemFree(file_path); CoTaskMemFree(file_path);
} }
result->Release(); result->Release();
@ -681,7 +681,7 @@ void DisplayServerWindows::_thread_fd_monitor(void *p_ud) {
PWSTR file_path = nullptr; PWSTR file_path = nullptr;
hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path); hr = result->GetDisplayName(SIGDN_FILESYSPATH, &file_path);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
file_names.push_back(String::utf16((const char16_t *)file_path).replace("\\", "/").trim_prefix(R"(\\?\)")); file_names.push_back(String::utf16((const char16_t *)file_path).replace_char('\\', '/').trim_prefix(R"(\\?\)"));
CoTaskMemFree(file_path); CoTaskMemFree(file_path);
} }
result->Release(); result->Release();
@ -7165,7 +7165,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
HKEY key; HKEY key;
if (RegOpenKeyW(HKEY_CURRENT_USER_LOCAL_SETTINGS, L"Software\\Microsoft\\Windows\\Shell\\MuiCache", &key) == ERROR_SUCCESS) { if (RegOpenKeyW(HKEY_CURRENT_USER_LOCAL_SETTINGS, L"Software\\Microsoft\\Windows\\Shell\\MuiCache", &key) == ERROR_SUCCESS) {
Char16String cs_name = name.utf16(); Char16String cs_name = name.utf16();
String value_name = OS::get_singleton()->get_executable_path().replace("/", "\\") + ".FriendlyAppName"; String value_name = OS::get_singleton()->get_executable_path().replace_char('/', '\\') + ".FriendlyAppName";
RegSetValueExW(key, (LPCWSTR)value_name.utf16().get_data(), 0, REG_SZ, (const BYTE *)cs_name.get_data(), cs_name.size() * sizeof(WCHAR)); RegSetValueExW(key, (LPCWSTR)value_name.utf16().get_data(), 0, REG_SZ, (const BYTE *)cs_name.get_data(), cs_name.size() * sizeof(WCHAR));
RegCloseKey(key); RegCloseKey(key);
} }

View file

@ -54,10 +54,10 @@ static String fix_path(const String &p_path) {
size_t str_len = GetCurrentDirectoryW(0, nullptr); size_t str_len = GetCurrentDirectoryW(0, nullptr);
current_dir_name.resize(str_len + 1); current_dir_name.resize(str_len + 1);
GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw()); GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
path = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/").path_join(path); path = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace_char('\\', '/').path_join(path);
} }
path = path.simplify_path(); path = path.simplify_path();
path = path.replace("/", "\\"); path = path.replace_char('/', '\\');
if (path.size() >= MAX_PATH && !path.is_network_share_path() && !path.begins_with(R"(\\?\)")) { if (path.size() >= MAX_PATH && !path.is_network_share_path() && !path.begins_with(R"(\\?\)")) {
path = R"(\\?\)" + path; path = R"(\\?\)" + path;
} }

View file

@ -113,10 +113,10 @@ static String fix_path(const String &p_path) {
size_t str_len = GetCurrentDirectoryW(0, nullptr); size_t str_len = GetCurrentDirectoryW(0, nullptr);
current_dir_name.resize(str_len + 1); current_dir_name.resize(str_len + 1);
GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw()); GetCurrentDirectoryW(current_dir_name.size(), (LPWSTR)current_dir_name.ptrw());
path = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace("\\", "/").path_join(path); path = String::utf16((const char16_t *)current_dir_name.get_data()).trim_prefix(R"(\\?\)").replace_char('\\', '/').path_join(path);
} }
path = path.simplify_path(); path = path.simplify_path();
path = path.replace("/", "\\"); path = path.replace_char('/', '\\');
if (path.size() >= MAX_PATH && !path.is_network_share_path() && !path.begins_with(R"(\\?\)")) { if (path.size() >= MAX_PATH && !path.is_network_share_path() && !path.begins_with(R"(\\?\)")) {
path = R"(\\?\)" + path; path = R"(\\?\)" + path;
} }
@ -195,7 +195,7 @@ bool OS_Windows::is_using_con_wrapper() const {
WCHAR proc_name[MAX_PATH]; WCHAR proc_name[MAX_PATH];
DWORD len = MAX_PATH; DWORD len = MAX_PATH;
if (QueryFullProcessImageNameW(process, 0, &proc_name[0], &len)) { if (QueryFullProcessImageNameW(process, 0, &proc_name[0], &len)) {
String name = String::utf16((const char16_t *)&proc_name[0], len).replace("\\", "/").to_lower(); String name = String::utf16((const char16_t *)&proc_name[0], len).replace_char('\\', '/').to_lower();
if (name == exe_name) { if (name == exe_name) {
found_exe = true; found_exe = true;
} }
@ -1879,7 +1879,7 @@ Vector<String> OS_Windows::get_system_font_path_for_text(const String &p_font_na
if (FAILED(hr)) { if (FAILED(hr)) {
continue; continue;
} }
String fpath = String::utf16((const char16_t *)&file_path[0]).replace("\\", "/"); String fpath = String::utf16((const char16_t *)&file_path[0]).replace_char('\\', '/');
WIN32_FIND_DATAW d; WIN32_FIND_DATAW d;
HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d); HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d);
@ -1958,7 +1958,7 @@ String OS_Windows::get_system_font_path(const String &p_font_name, int p_weight,
if (FAILED(hr)) { if (FAILED(hr)) {
continue; continue;
} }
String fpath = String::utf16((const char16_t *)&file_path[0]).replace("\\", "/"); String fpath = String::utf16((const char16_t *)&file_path[0]).replace_char('\\', '/');
WIN32_FIND_DATAW d; WIN32_FIND_DATAW d;
HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d); HANDLE fnd = FindFirstFileW((LPCWSTR)&file_path[0], &d);
@ -1978,7 +1978,7 @@ String OS_Windows::get_system_font_path(const String &p_font_name, int p_weight,
String OS_Windows::get_executable_path() const { String OS_Windows::get_executable_path() const {
WCHAR bufname[4096]; WCHAR bufname[4096];
GetModuleFileNameW(nullptr, bufname, 4096); GetModuleFileNameW(nullptr, bufname, 4096);
String s = String::utf16((const char16_t *)bufname).replace("\\", "/"); String s = String::utf16((const char16_t *)bufname).replace_char('\\', '/');
return s; return s;
} }
@ -2195,14 +2195,14 @@ String OS_Windows::get_locale() const {
} }
if (lang == wl->main_lang && sublang == wl->sublang) { if (lang == wl->main_lang && sublang == wl->sublang) {
return String(wl->locale).replace("-", "_"); return String(wl->locale).replace_char('-', '_');
} }
wl++; wl++;
} }
if (!neutral.is_empty()) { if (!neutral.is_empty()) {
return String(neutral).replace("-", "_"); return String(neutral).replace_char('-', '_');
} }
return "en"; return "en";
@ -2331,7 +2331,7 @@ uint64_t OS_Windows::get_embedded_pck_offset() const {
String OS_Windows::get_config_path() const { String OS_Windows::get_config_path() const {
if (has_environment("APPDATA")) { if (has_environment("APPDATA")) {
return get_environment("APPDATA").replace("\\", "/"); return get_environment("APPDATA").replace_char('\\', '/');
} }
return "."; return ".";
} }
@ -2344,7 +2344,7 @@ String OS_Windows::get_cache_path() const {
static String cache_path_cache; static String cache_path_cache;
if (cache_path_cache.is_empty()) { if (cache_path_cache.is_empty()) {
if (has_environment("LOCALAPPDATA")) { if (has_environment("LOCALAPPDATA")) {
cache_path_cache = get_environment("LOCALAPPDATA").replace("\\", "/"); cache_path_cache = get_environment("LOCALAPPDATA").replace_char('\\', '/');
} }
if (cache_path_cache.is_empty()) { if (cache_path_cache.is_empty()) {
cache_path_cache = get_temp_path(); cache_path_cache = get_temp_path();
@ -2374,7 +2374,7 @@ String OS_Windows::get_temp_path() const {
temp_path_cache = get_config_path(); temp_path_cache = get_config_path();
} }
} }
return temp_path_cache.replace("\\", "/").trim_suffix("/"); return temp_path_cache.replace_char('\\', '/').trim_suffix("/");
} }
// Get properly capitalized engine name for system paths // Get properly capitalized engine name for system paths
@ -2415,13 +2415,13 @@ String OS_Windows::get_system_dir(SystemDir p_dir, bool p_shared_storage) const
PWSTR szPath; PWSTR szPath;
HRESULT res = SHGetKnownFolderPath(id, 0, nullptr, &szPath); HRESULT res = SHGetKnownFolderPath(id, 0, nullptr, &szPath);
ERR_FAIL_COND_V(res != S_OK, String()); ERR_FAIL_COND_V(res != S_OK, String());
String path = String::utf16((const char16_t *)szPath).replace("\\", "/"); String path = String::utf16((const char16_t *)szPath).replace_char('\\', '/');
CoTaskMemFree(szPath); CoTaskMemFree(szPath);
return path; return path;
} }
String OS_Windows::get_user_data_dir(const String &p_user_dir) const { String OS_Windows::get_user_data_dir(const String &p_user_dir) const {
return get_data_path().path_join(p_user_dir).replace("\\", "/"); return get_data_path().path_join(p_user_dir).replace_char('\\', '/');
} }
String OS_Windows::get_unique_id() const { String OS_Windows::get_unique_id() const {

View file

@ -522,7 +522,7 @@ void FileDialog::_action_pressed() {
} else if (mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_DIR) { } else if (mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_DIR) {
String path = dir_access->get_current_dir(); String path = dir_access->get_current_dir();
path = path.replace("\\", "/"); path = path.replace_char('\\', '/');
TreeItem *item = tree->get_selected(); TreeItem *item = tree->get_selected();
if (item) { if (item) {
Dictionary d = item->get_metadata(0); Dictionary d = item->get_metadata(0);

View file

@ -1934,7 +1934,7 @@ void RichTextLabel::_accessibility_update_line(RID p_id, ItemFrame *p_frame, int
// Process text. // Process text.
const RID &para_rid = l.text_buf->get_rid(); const RID &para_rid = l.text_buf->get_rid();
String l_text = TS->shaped_get_text(para_rid).replace(String::chr(0xfffc), "").strip_edges(); String l_text = TS->shaped_get_text(para_rid).remove_char(0xfffc).strip_edges();
if (l.dc_item) { if (l.dc_item) {
ItemDropcap *dc = static_cast<ItemDropcap *>(l.dc_item); ItemDropcap *dc = static_cast<ItemDropcap *>(l.dc_item);
l_text = dc->text + l_text; l_text = dc->text + l_text;

View file

@ -108,7 +108,7 @@ void SpinBox::_update_text(bool p_only_update_if_value_changed) {
} }
} }
if (!accepted && update_on_text_changed && !line_edit->get_text().replace(",", ".").contains_char('.')) { if (!accepted && update_on_text_changed && !line_edit->get_text().replace_char(',', '.').contains_char('.')) {
value = String::num(get_value(), 0); value = String::num(get_value(), 0);
} }
@ -124,7 +124,7 @@ void SpinBox::_text_submitted(const String &p_string) {
if (update_on_text_changed) { if (update_on_text_changed) {
// Convert commas ',' to dots '.' for French/German etc. keyboard layouts. // Convert commas ',' to dots '.' for French/German etc. keyboard layouts.
text = p_string.replace(",", "."); text = p_string.replace_char(',', '.');
if (!text.begins_with(".") && p_string.ends_with(".")) { if (!text.begins_with(".") && p_string.ends_with(".")) {
return; return;
@ -140,7 +140,7 @@ void SpinBox::_text_submitted(const String &p_string) {
Ref<Expression> expr; Ref<Expression> expr;
expr.instantiate(); expr.instantiate();
text = text.replace(";", ","); text = text.replace_char(';', ',');
text = TS->parse_number(text); text = TS->parse_number(text);
// Ignore the prefix and suffix in the expression. // Ignore the prefix and suffix in the expression.
text = text.trim_prefix(prefix + " ").trim_suffix(" " + suffix); text = text.trim_prefix(prefix + " ").trim_suffix(" " + suffix);
@ -175,7 +175,7 @@ void SpinBox::_text_changed(const String &p_string) {
_text_submitted(p_string); _text_submitted(p_string);
String text = p_string.replace(",", "."); String text = p_string.replace_char(',', '.');
// Line edit 'set_text' method resets the cursor position so we need to undo that. // Line edit 'set_text' method resets the cursor position so we need to undo that.
if (update_on_text_changed && !text.begins_with(".")) { if (update_on_text_changed && !text.begins_with(".")) {

View file

@ -39,12 +39,7 @@
#endif // PHYSICS_3D_DISABLED #endif // PHYSICS_3D_DISABLED
String ImporterMesh::validate_blend_shape_name(const String &p_name) { String ImporterMesh::validate_blend_shape_name(const String &p_name) {
String name = p_name; return p_name.replace_char(':', '_');
const char *characters = ":";
for (const char *p = characters; *p; p++) {
name = name.replace(String::chr(*p), "_");
}
return name;
} }
void ImporterMesh::add_blend_shape(const String &p_name) { void ImporterMesh::add_blend_shape(const String &p_name) {

View file

@ -42,10 +42,8 @@ bool AnimationLibrary::is_valid_library_name(const String &p_name) {
String AnimationLibrary::validate_library_name(const String &p_name) { String AnimationLibrary::validate_library_name(const String &p_name) {
String name = p_name; String name = p_name;
const char *characters = "/:,["; static const char *characters = "/:,[";
for (const char *p = characters; *p; p++) { name.replace_chars(characters, '_');
name = name.replace(String::chr(*p), "_");
}
return name; return name;
} }

View file

@ -177,7 +177,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (!nparent && (n.parent & FLAG_ID_IS_PATH)) { if (!nparent && (n.parent & FLAG_ID_IS_PATH)) {
WARN_PRINT(String("Parent path '" + String(node_paths[n.parent & FLAG_MASK]) + "' for node '" + String(snames[n.name]) + "' has vanished when instantiating: '" + get_path() + "'.").ascii().get_data()); WARN_PRINT(String("Parent path '" + String(node_paths[n.parent & FLAG_MASK]) + "' for node '" + String(snames[n.name]) + "' has vanished when instantiating: '" + get_path() + "'.").ascii().get_data());
old_parent_path = String(node_paths[n.parent & FLAG_MASK]).trim_prefix("./").replace("/", "@"); old_parent_path = String(node_paths[n.parent & FLAG_MASK]).trim_prefix("./").replace_char('/', '@');
nparent = ret_nodes[0]; nparent = ret_nodes[0];
} }
#endif #endif

View file

@ -6839,7 +6839,7 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ
// Only the instance that is not a local device and is also the singleton is allowed to manage a pipeline cache. // Only the instance that is not a local device and is also the singleton is allowed to manage a pipeline cache.
pipeline_cache_file_path = vformat("user://vulkan/pipelines.%s.%s", pipeline_cache_file_path = vformat("user://vulkan/pipelines.%s.%s",
OS::get_singleton()->get_current_rendering_method(), OS::get_singleton()->get_current_rendering_method(),
device.name.validate_filename().replace(" ", "_").to_lower()); device.name.validate_filename().replace_char(' ', '_').to_lower());
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
pipeline_cache_file_path += ".editor"; pipeline_cache_file_path += ".editor";
} }

View file

@ -112,7 +112,7 @@ TEST_CASE("[ProjectSettings] localize_path") {
TestProjectSettingsInternalsAccessor::resource_path() = DirAccess::create(DirAccess::ACCESS_FILESYSTEM)->get_current_dir(); TestProjectSettingsInternalsAccessor::resource_path() = DirAccess::create(DirAccess::ACCESS_FILESYSTEM)->get_current_dir();
String root_path = ProjectSettings::get_singleton()->get_resource_path(); String root_path = ProjectSettings::get_singleton()->get_resource_path();
#ifdef WINDOWS_ENABLED #ifdef WINDOWS_ENABLED
String root_path_win = ProjectSettings::get_singleton()->get_resource_path().replace("/", "\\"); String root_path_win = ProjectSettings::get_singleton()->get_resource_path().replace_char('/', '\\');
#endif #endif
CHECK_EQ(ProjectSettings::get_singleton()->localize_path("filename"), "res://filename"); CHECK_EQ(ProjectSettings::get_singleton()->localize_path("filename"), "res://filename");

View file

@ -476,6 +476,27 @@ TEST_CASE("[String] Find and replace") {
MULTICHECK_STRING_STRING_EQ(s, replacen, "Y", "Y", "HappY BirthdaY, Anna!"); MULTICHECK_STRING_STRING_EQ(s, replacen, "Y", "Y", "HappY BirthdaY, Anna!");
} }
TEST_CASE("[String] replace_char") {
String s = "Banana";
CHECK(s.replace_char('n', 'x') == "Baxaxa");
CHECK(s.replace_char('\0', 'x') == "Banana");
ERR_PRINT_OFF
CHECK(s.replace_char('n', '\0') == "Banana");
ERR_PRINT_ON
}
TEST_CASE("[String] replace_chars") {
String s = "Banana";
CHECK(s.replace_chars(String("Bn"), 'x') == "xaxaxa");
CHECK(s.replace_chars("Bn", 'x') == "xaxaxa");
CHECK(s.replace_chars(String(), 'x') == "Banana");
CHECK(s.replace_chars("", 'x') == "Banana");
ERR_PRINT_OFF
CHECK(s.replace_chars(String("Bn"), '\0') == "Banana");
CHECK(s.replace_chars("Bn", '\0') == "Banana");
ERR_PRINT_ON
}
TEST_CASE("[String] Insertion") { TEST_CASE("[String] Insertion") {
String s = "Who is Frederic?"; String s = "Who is Frederic?";
s = s.insert(s.find("?"), " Chopin"); s = s.insert(s.find("?"), " Chopin");