[Core] Add case-insensitive String::containsn

This commit is contained in:
A Thousand Ships 2024-05-06 10:26:10 +02:00
parent 281fe39929
commit b4c6cc7d82
No known key found for this signature in database
GPG key ID: 2033189A662F8BD7
23 changed files with 64 additions and 32 deletions

View file

@ -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;

View file

@ -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<bool (String::*)(const String &) const>(&String::contains), sarray("what"), varray());
bind_string_methodv(containsn, static_cast<bool (String::*)(const String &) const>(&String::containsn), sarray("what"), varray());
bind_string_method(is_absolute_path, sarray(), varray());
bind_string_method(is_relative_path, sarray(), varray());

View file

@ -126,7 +126,7 @@
[/codeblock]
</description>
</method>
<method name="contains" qualifiers="const" keywords="includes, has">
<method name="contains" qualifiers="const">
<return type="bool" />
<param index="0" name="what" type="String" />
<description>
@ -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].
</description>
</method>
<method name="containsn" qualifiers="const">
<return type="bool" />
<param index="0" name="what" type="String" />
<description>
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].
</description>
</method>
<method name="count" qualifiers="const">

View file

@ -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].
</description>
</method>
<method name="containsn" qualifiers="const">
<return type="bool" />
<param index="0" name="what" type="String" />
<description>
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].
</description>
</method>
<method name="count" qualifiers="const">

View file

@ -157,7 +157,7 @@ Config::Config() {
continue;
}
if (renderer.findn(v) != -1) {
if (renderer.containsn(v)) {
use_depth_prepass = false;
}
}

View file

@ -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);
}

View file

@ -282,7 +282,7 @@ List<MethodInfo> ConnectDialog::_filter_method_list(const List<MethodInfo> &p_me
List<MethodInfo> 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;
}

View file

@ -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());
}

View file

@ -40,7 +40,7 @@
bool EditorHelpSearch::_all_terms_in_name(const Vector<String> &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);
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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) {

View file

@ -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;
}

View file

@ -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<VisualShaderNode> vsn;

View file

@ -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);

View file

@ -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;
}

View file

@ -77,7 +77,7 @@ void EditorSceneExporterGLTFSettings::_get_property_list(List<PropertyInfo> *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);

View file

@ -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);
}

View file

@ -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();
}
}

View file

@ -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);