diff --git a/core/string/ustring.h b/core/string/ustring.h index a020c7d372e5..9df2d56e8004 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -429,6 +429,8 @@ public: _FORCE_INLINE_ bool is_empty() const { return length() == 0; } _FORCE_INLINE_ bool contains(const char *p_str) const { return find(p_str) != -1; } _FORCE_INLINE_ bool contains(const String &p_str) const { return find(p_str) != -1; } + _FORCE_INLINE_ bool containsn(const char *p_str) const { return findn(p_str) != -1; } + _FORCE_INLINE_ bool containsn(const String &p_str) const { return findn(p_str) != -1; } // path functions bool is_absolute_path() const; diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index c5861f3fbb4a..9b7777f480fe 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1707,6 +1707,7 @@ static void _register_variant_builtin_methods() { bind_string_method(sha256_buffer, sarray(), varray()); bind_string_method(is_empty, sarray(), varray()); bind_string_methodv(contains, static_cast(&String::contains), sarray("what"), varray()); + bind_string_methodv(containsn, static_cast(&String::containsn), sarray("what"), varray()); bind_string_method(is_absolute_path, sarray(), varray()); bind_string_method(is_relative_path, sarray(), varray()); diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 13bf994e8361..450e483f696a 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -126,7 +126,7 @@ [/codeblock] - + @@ -142,7 +142,15 @@ GD.Print("team".Contains("I")); // Prints false [/csharp] [/codeblocks] - If you need to know where [param what] is within the string, use [method find]. + If you need to know where [param what] is within the string, use [method find]. See also [method containsn]. + + + + + + + Returns [code]true[/code] if the string contains [param what], [b]ignoring case[/b]. + If you need to know where [param what] is within the string, use [method findn]. See also [method contains]. diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml index fbb73fd4835e..76586b796801 100644 --- a/doc/classes/StringName.xml +++ b/doc/classes/StringName.xml @@ -126,7 +126,15 @@ GD.Print("team".Contains("I")); // Prints false [/csharp] [/codeblocks] - If you need to know where [param what] is within the string, use [method find]. + If you need to know where [param what] is within the string, use [method find]. See also [method containsn]. + + + + + + + Returns [code]true[/code] if the string contains [param what], [b]ignoring case[/b]. + If you need to know where [param what] is within the string, use [method findn]. See also [method contains]. diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 1a41b60836e0..6b5e22778264 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -157,7 +157,7 @@ Config::Config() { continue; } - if (renderer.findn(v) != -1) { + if (renderer.containsn(v)) { use_depth_prepass = false; } } diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 9c7f4c33d632..f21a0816ca30 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -7122,7 +7122,7 @@ void AnimationTrackEditor::_pick_track_select_recursive(TreeItem *p_item, const NodePath np = p_item->get_metadata(0); Node *node = get_node_or_null(np); - if (node && !p_filter.is_empty() && ((String)node->get_name()).findn(p_filter) != -1) { + if (node && !p_filter.is_empty() && ((String)node->get_name()).containsn(p_filter)) { p_select_candidates.push_back(node); } diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 787cae22cbb3..478067629e70 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -282,7 +282,7 @@ List ConnectDialog::_filter_method_list(const List &p_me List ret; for (const MethodInfo &mi : p_methods) { - if (!p_search_string.is_empty() && mi.name.findn(p_search_string) == -1) { + if (!p_search_string.is_empty() && !mi.name.containsn(p_search_string)) { continue; } diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.h b/editor/debugger/debug_adapter/debug_adapter_parser.h index 9860e964988c..8fd2c2b3e26e 100644 --- a/editor/debugger/debug_adapter/debug_adapter_parser.h +++ b/editor/debugger/debug_adapter/debug_adapter_parser.h @@ -50,7 +50,7 @@ private: if (p_path.contains("\\")) { String project_path = ProjectSettings::get_singleton()->get_resource_path(); String path = p_path.replace("\\", "/"); - return path.findn(project_path) != -1; + return path.containsn(project_path); } return p_path.begins_with(ProjectSettings::get_singleton()->get_resource_path()); } diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index ff381d68c050..f2154f03c376 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -40,7 +40,7 @@ bool EditorHelpSearch::_all_terms_in_name(const Vector &p_terms, const String &p_name) const { for (int i = 0; i < p_terms.size(); i++) { - if (p_name.findn(p_terms[i]) < 0) { + if (!p_name.containsn(p_terms[i])) { return false; } } @@ -109,7 +109,7 @@ Dictionary EditorHelpSearch::_native_search_cb(const String &p_search_string, in if (class_doc.name.is_empty()) { continue; } - if (class_doc.name.findn(term) > -1) { + if (class_doc.name.containsn(term)) { ret[vformat("class_name:%s", class_doc.name)] = class_doc.name; } if (term.length() > 1 || term == "@") { @@ -746,7 +746,7 @@ bool EditorHelpSearch::Runner::_match_string(const String &p_term, const String if (search_flags & SEARCH_CASE_SENSITIVE) { return p_string.find(p_term) > -1; } else { - return p_string.findn(p_term) > -1; + return p_string.containsn(p_term); } } diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 7c69ac589a22..9599479c8326 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -52,7 +52,7 @@ #include "scene/resources/style_box_flat.h" bool EditorInspector::_property_path_matches(const String &p_property_path, const String &p_filter, EditorPropertyNameProcessor::Style p_style) { - if (p_property_path.findn(p_filter) != -1) { + if (p_property_path.containsn(p_filter)) { return true; } diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index b8da550d8a74..ab4950f01b38 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -322,7 +322,7 @@ void EditorLog::_rebuild_log() { bool EditorLog::_check_display_message(LogMessage &p_message) { bool filter_active = type_filter_map[p_message.type]->is_active(); String search_text = search_box->get_text(); - bool search_match = search_text.is_empty() || p_message.text.findn(search_text) > -1; + bool search_match = search_text.is_empty() || p_message.text.containsn(search_text); return filter_active && search_match; } diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index f13af8e4ca6d..22120bfc01ec 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -36,7 +36,7 @@ #include "editor/themes/editor_scale.h" static bool _property_path_matches(const String &p_property_path, const String &p_filter, EditorPropertyNameProcessor::Style p_style) { - if (p_property_path.findn(p_filter) != -1) { + if (p_property_path.containsn(p_filter)) { return true; } diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp index 707be8438117..16ac80f7e1b2 100644 --- a/editor/import/3d/resource_importer_scene.cpp +++ b/editor/import/3d/resource_importer_scene.cpp @@ -387,7 +387,7 @@ static bool _teststr(const String &p_what, const String &p_str) { what = what.substr(0, what.length() - 1); } - if (what.findn("$" + p_str) != -1) { //blender and other stuff + if (what.containsn("$" + p_str)) { // Blender and other stuff. return true; } if (what.to_lower().ends_with("-" + p_str)) { //collada only supports "_" and "-" besides letters @@ -410,7 +410,7 @@ static String _fixstr(const String &p_what, const String &p_str) { String end = p_what.substr(what.length(), p_what.length() - what.length()); - if (what.findn("$" + p_str) != -1) { //blender and other stuff + if (what.containsn("$" + p_str)) { // Blender and other stuff. return what.replace("$" + p_str, "") + end; } if (what.to_lower().ends_with("-" + p_str)) { //collada only supports "_" and "-" besides letters diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp index a667f94a6296..143de82765ee 100644 --- a/editor/input_event_configuration_dialog.cpp +++ b/editor/input_event_configuration_dialog.cpp @@ -285,7 +285,7 @@ void InputEventConfigurationDialog::_update_input_list() { for (int i = 0; i < keycode_get_count(); i++) { String name = keycode_get_name_by_index(i); - if (!search_term.is_empty() && name.findn(search_term) == -1) { + if (!search_term.is_empty() && !name.containsn(search_term)) { continue; } @@ -309,7 +309,7 @@ void InputEventConfigurationDialog::_update_input_list() { mb->set_button_index(mouse_buttons[i]); String desc = EventListenerLineEdit::get_event_text(mb, false); - if (!search_term.is_empty() && desc.findn(search_term) == -1) { + if (!search_term.is_empty() && !desc.containsn(search_term)) { continue; } @@ -332,7 +332,7 @@ void InputEventConfigurationDialog::_update_input_list() { joyb->set_button_index((JoyButton)i); String desc = EventListenerLineEdit::get_event_text(joyb, false); - if (!search_term.is_empty() && desc.findn(search_term) == -1) { + if (!search_term.is_empty() && !desc.containsn(search_term)) { continue; } @@ -358,7 +358,7 @@ void InputEventConfigurationDialog::_update_input_list() { joym->set_axis_value(direction); String desc = EventListenerLineEdit::get_event_text(joym, false); - if (!search_term.is_empty() && desc.findn(search_term) == -1) { + if (!search_term.is_empty() && !desc.containsn(search_term)) { continue; } diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 2f479527f3b1..62f63671ceca 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -374,7 +374,7 @@ void ScriptEditorQuickOpen::_update_search() { for (int i = 0; i < functions.size(); i++) { String file = functions[i]; - if ((search_box->get_text().is_empty() || file.findn(search_box->get_text()) != -1)) { + if ((search_box->get_text().is_empty() || file.containsn(search_box->get_text()))) { TreeItem *ti = search_options->create_item(root); ti->set_text(0, file); if (root->get_first_child() == ti) { diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 166ed05748c7..4cc88aab3486 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -106,7 +106,7 @@ void ThemeItemImportTree::_update_items_tree() { type_node->set_checked(IMPORT_ITEM_DATA, false); type_node->set_editable(IMPORT_ITEM_DATA, true); - bool is_matching_filter = (filter_text.is_empty() || type_name.findn(filter_text) > -1); + bool is_matching_filter = (filter_text.is_empty() || type_name.containsn(filter_text)); bool has_filtered_items = false; for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) { @@ -120,7 +120,7 @@ void ThemeItemImportTree::_update_items_tree() { for (const StringName &F : names) { String item_name = (String)F; - bool is_item_matching_filter = (item_name.findn(filter_text) > -1); + bool is_item_matching_filter = item_name.containsn(filter_text); if (!filter_text.is_empty() && !is_matching_filter && !is_item_matching_filter) { continue; } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index e3f7aa5e6d69..35db52a42e41 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1957,7 +1957,7 @@ void VisualShaderEditor::_update_options_menu() { } for (int i = 0; i < add_options.size(); i++) { - if (!use_filter || add_options[i].name.findn(filter) != -1) { + if (!use_filter || add_options[i].name.containsn(filter)) { // port type filtering if (members_output_port_type != VisualShaderNode::PORT_TYPE_MAX || members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) { Ref vsn; diff --git a/editor/project_manager/project_list.cpp b/editor/project_manager/project_list.cpp index d125754dd72e..b7520abc99a8 100644 --- a/editor/project_manager/project_list.cpp +++ b/editor/project_manager/project_list.cpp @@ -545,7 +545,7 @@ void ProjectList::sort_projects() { } // When searching, display projects whose name or path contain the search term and whose tags match the searched tags. - item_visible = !missing_tags && (search_term.is_empty() || item.project_name.findn(search_term) != -1 || search_path.findn(search_term) != -1); + item_visible = !missing_tags && (search_term.is_empty() || item.project_name.containsn(search_term) || search_path.containsn(search_term)); } item.control->set_visible(item_visible); diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp index eef68d918a1d..77ab629ba635 100644 --- a/editor/property_selector.cpp +++ b/editor/property_selector.cpp @@ -190,7 +190,7 @@ void PropertySelector::_update_search() { continue; } - if (!search_box->get_text().is_empty() && E.name.findn(search_text) == -1) { + if (!search_box->get_text().is_empty() && !E.name.containsn(search_text)) { continue; } @@ -203,7 +203,7 @@ void PropertySelector::_update_search() { item->set_metadata(0, E.name); item->set_icon(0, type_icons[E.type]); - if (!found && !search_box->get_text().is_empty() && E.name.findn(search_text) != -1) { + if (!found && !search_box->get_text().is_empty() && E.name.containsn(search_text)) { item->select(0); found = true; } @@ -281,7 +281,7 @@ void PropertySelector::_update_search() { continue; } - if (!search_box->get_text().is_empty() && name.findn(search_text) == -1) { + if (!search_box->get_text().is_empty() && !name.containsn(search_text)) { continue; } @@ -330,7 +330,7 @@ void PropertySelector::_update_search() { item->set_metadata(0, name); item->set_selectable(0, true); - if (!found && !search_box->get_text().is_empty() && name.findn(search_text) != -1) { + if (!found && !search_box->get_text().is_empty() && name.containsn(search_text)) { item->select(0); found = true; } diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp index d11300343ab8..fc184c934285 100644 --- a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp +++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp @@ -77,7 +77,7 @@ void EditorSceneExporterGLTFSettings::_get_property_list(List *p_l for (PropertyInfo prop : _property_list) { if (prop.name == "lossy_quality") { String image_format = get("image_format"); - bool is_image_format_lossy = image_format == "JPEG" || image_format.findn("Lossy") != -1; + bool is_image_format_lossy = image_format == "JPEG" || image_format.containsn("Lossy"); prop.usage = is_image_format_lossy ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_STORAGE; } p_list->push_back(prop); diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp index 73e53a6a07e2..08e7ba360a22 100644 --- a/modules/multiplayer/editor/replication_editor.cpp +++ b/modules/multiplayer/editor/replication_editor.cpp @@ -81,7 +81,7 @@ void ReplicationEditor::_pick_node_select_recursive(TreeItem *p_item, const Stri NodePath np = p_item->get_metadata(0); Node *node = get_node(np); - if (!p_filter.is_empty() && ((String)node->get_name()).findn(p_filter) != -1) { + if (!p_filter.is_empty() && ((String)node->get_name()).containsn(p_filter)) { p_select_candidates.push_back(node); } diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 0f8978436977..3469b806a6e7 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -239,7 +239,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) { String new_request; for (const String &E : rheaders) { - if (E.findn("Location: ") != -1) { + if (E.containsn("Location: ")) { new_request = E.substr(9, E.length()).strip_edges(); } } diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index 18828c3b70bf..cf57183a025c 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -297,6 +297,19 @@ TEST_CASE("[String] Contains") { CHECK(!s.contains(String("\\char_test.tscn"))); } +TEST_CASE("[String] Contains case insensitive") { + String s = "C:\\Godot\\project\\string_test.tscn"; + CHECK(s.containsn("Godot")); + CHECK(s.containsn("godot")); + CHECK(s.containsn(String("Project\\string_test"))); + CHECK(s.containsn(String("\\string_Test.tscn"))); + + CHECK(!s.containsn("Godoh")); + CHECK(!s.containsn("godoh")); + CHECK(!s.containsn(String("project\\string test"))); + CHECK(!s.containsn(String("\\char_test.tscn"))); +} + TEST_CASE("[String] Test chr") { CHECK(String::chr('H') == "H"); CHECK(String::chr(0x3012)[0] == 0x3012); @@ -376,7 +389,7 @@ TEST_CASE("[String] Find") { MULTICHECK_STRING_INT_EQ(s, rfind, "", 15, -1); } -TEST_CASE("[String] Find no case") { +TEST_CASE("[String] Find case insensitive") { String s = "Pretty Whale Whale"; MULTICHECK_STRING_EQ(s, findn, "WHA", 7); MULTICHECK_STRING_INT_EQ(s, findn, "WHA", 9, 13);