diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 2e219cf0c..1f27ec501 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -2861,6 +2861,7 @@ g_string_insert_unichar g_string_insert_len g_string_overwrite g_string_overwrite_len +g_string_replace g_string_erase g_string_truncate g_string_set_size diff --git a/glib/gstring.c b/glib/gstring.c index 85294258b..030d75316 100644 --- a/glib/gstring.c +++ b/glib/gstring.c @@ -953,6 +953,55 @@ g_string_erase (GString *string, return string; } +/** + * g_string_replace: + * @string: a #GString + * @find: the string to find in @string + * @replace: the string to insert in place of @find + * @limit: the maximum instances of @find to replace with @replace, or `0` for + * no limit + * + * Replaces the string @find with the string @replace in a #GString up to + * @limit times. If the number of instances of @find in the #GString is + * less than @limit, all instances are replaced. If the number of + * instances is `0`, all instances of @find are replaced. + * + * Returns: the number of find and replace operations performed. + * + * Since: 2.68 + */ +guint +g_string_replace (GString *string, + const gchar *find, + const gchar *replace, + guint limit) +{ + gsize f_len, r_len, pos; + gchar *cur, *next; + gint n = 0; + + g_return_val_if_fail (string != NULL, 0); + g_return_val_if_fail (find != NULL, 0); + g_return_val_if_fail (replace != NULL, 0); + + f_len = strlen (find); + r_len = strlen (replace); + cur = string->str; + + while ((next = strstr (cur, find)) != NULL) + { + pos = next - string->str; + g_string_erase (string, pos, f_len); + g_string_insert (string, pos, replace); + cur = string->str + pos + r_len; + n++; + if (n == limit) + break; + } + + return n; +} + /** * g_string_ascii_down: * @string: a GString diff --git a/glib/gstring.h b/glib/gstring.h index e1b2e7fca..eec4c138f 100644 --- a/glib/gstring.h +++ b/glib/gstring.h @@ -127,6 +127,11 @@ GLIB_AVAILABLE_IN_ALL GString* g_string_erase (GString *string, gssize pos, gssize len); +GLIB_AVAILABLE_IN_2_68 +guint g_string_replace (GString *string, + const gchar *find, + const gchar *replace, + guint limit); GLIB_AVAILABLE_IN_ALL GString* g_string_ascii_down (GString *string); GLIB_AVAILABLE_IN_ALL diff --git a/glib/tests/string.c b/glib/tests/string.c index cb5df4cec..819b192fb 100644 --- a/glib/tests/string.c +++ b/glib/tests/string.c @@ -495,6 +495,34 @@ test_string_to_bytes (void) g_bytes_unref (bytes); } +static void +test_string_replace (void) +{ + GString *s; + gint n; + + s = g_string_new ("foo bar foo baz foo bar foobarbaz"); + + n = g_string_replace (s, "bar", "baz", 0); + g_assert_cmpstr ("foo baz foo baz foo baz foobazbaz", ==, s->str); + g_assert_cmpint (n, ==, 3); + + n = g_string_replace (s, "baz", "bar", 3); + g_assert_cmpstr ("foo bar foo bar foo bar foobazbaz", ==, s->str); + g_assert_cmpint (n, ==, 3); + + n = g_string_replace (s, "foobar", "bar", 1); + g_assert_cmpstr ("foo bar foo bar foo bar foobazbaz", ==, s->str); + g_assert_cmpint (n, ==, 0); + + s = g_string_assign (s, "aaaaaaaa"); + n = g_string_replace (s, "a", "abcdefghijkl", 0); + g_assert_cmpstr ("abcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijkl", + ==, s->str); + + g_string_free (s, TRUE); +} + int main (int argc, char *argv[]) @@ -519,6 +547,7 @@ main (int argc, g_test_add_func ("/string/test-string-up-down", test_string_up_down); g_test_add_func ("/string/test-string-set-size", test_string_set_size); g_test_add_func ("/string/test-string-to-bytes", test_string_to_bytes); + g_test_add_func ("/string/test-string-replace", test_string_replace); return g_test_run(); }