Geometry Nodes: Find in String node

Add a node that finds the number of times a substring occurs in a string,
and the position of the start of the first match.

See the PR description for more rational and details.

Pull Request: https://projects.blender.org/blender/blender/pulls/129270
This commit is contained in:
SensArice
2024-12-24 17:12:19 +01:00
committed by Hans Goudey
parent 949b9638f5
commit 1098f434b0
5 changed files with 72 additions and 0 deletions

View File

@@ -553,6 +553,7 @@ class NODE_MT_category_GEO_TEXT(Menu):
node_add_menu.add_node_type(layout, "FunctionNodeSliceString")
layout.separator()
node_add_menu.add_node_type(layout, "FunctionNodeStringLength")
node_add_menu.add_node_type(layout, "FunctionNodeFindInString")
node_add_menu.add_node_type(layout, "GeometryNodeStringToCurves")
node_add_menu.add_node_type(layout, "FunctionNodeValueToString")
layout.separator()

View File

@@ -1412,6 +1412,7 @@ void node_tree_remove_layer_n(bNodeTree *ntree, Scene *scene, int layer_index);
#define FN_NODE_HASH_VALUE 1245
#define FN_NODE_INTEGER_MATH 1246
#define FN_NODE_MATRIX_DETERMINANT 1247
#define FN_NODE_FIND_IN_STRING 1248
/** \} */

View File

@@ -304,6 +304,7 @@ DefNode(FunctionNode, FN_NODE_SEPARATE_MATRIX, 0, SeparateMatrix, "Separate Matr
DefNode(FunctionNode, FN_NODE_SEPARATE_TRANSFORM, 0, SeparateTransform, "Separate Transform", "")
DefNode(FunctionNode, FN_NODE_SLICE_STRING, 0, SliceString, "Slice String", "")
DefNode(FunctionNode, FN_NODE_STRING_LENGTH, 0, StringLength, "String Length", "")
DefNode(FunctionNode, FN_NODE_FIND_IN_STRING, 0, FindInString, "Find In String","")
DefNode(FunctionNode, FN_NODE_TRANSFORM_DIRECTION, 0, TransformDirection, "Transform Direction", "")
DefNode(FunctionNode, FN_NODE_TRANSFORM_POINT, 0, TransformPoint, "Transform Point", "")
DefNode(FunctionNode, FN_NODE_TRANSPOSE_MATRIX, 0, TransposeMatrix, "Transpose Matrix", "")

View File

@@ -60,6 +60,7 @@ set(SRC
nodes/node_fn_transform_point.cc
nodes/node_fn_transpose_matrix.cc
nodes/node_fn_value_to_string.cc
nodes/node_fn_find_in_string.cc
node_function_util.cc

View File

@@ -0,0 +1,68 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_string_utf8.h"
#include "node_function_util.hh"
namespace blender::nodes::node_fn_find_in_string_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::String>("String").hide_label();
b.add_input<decl::String>("Search");
b.add_output<decl::Int>("First Found");
b.add_output<decl::Int>("Count");
}
static int string_find(const StringRef text, const StringRef token)
{
if (text.is_empty() || token.is_empty()) {
return 0;
}
const int pos = text.find(token, 0);
size_t r_len_bytes;
const int pos_n = BLI_strnlen_utf8_ex(text.data(), pos, &r_len_bytes);
return pos_n;
}
static int string_count(const StringRef text, const StringRef token)
{
if (text.is_empty() || token.is_empty()) {
return 0;
}
int count = 0;
const int match_len = token.size();
int pos = 0;
while ((pos = text.find(token, pos)) != StringRef::not_found) {
count++;
pos += match_len;
}
return count;
}
static void node_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static auto token_position_count = mf::build::SI2_SO2<std::string, std::string, int, int>(
"Find in String",
[](const std::string &text, const std::string &token, int &first, int &count) -> void {
first = string_find(text, token);
count = string_count(text, token);
});
builder.set_matching_fn(&token_position_count);
}
static void node_register()
{
static blender::bke::bNodeType ntype;
fn_node_type_base(&ntype, FN_NODE_FIND_IN_STRING, "Find in String", NODE_CLASS_CONVERTER);
ntype.declare = node_declare;
ntype.build_multi_function = node_build_multi_function;
blender::bke::node_register_type(&ntype);
}
NOD_REGISTER_NODE(node_register)
} // namespace blender::nodes::node_fn_find_in_string_cc