Add function string_replace_all[_str]

to replace all occurences of a string by another.
This commit is contained in:
Patrick Pelissier committed 2020-11-22 23:04:32 +01:00
1 parent 0b9e27fb7f
commit 55e7b3083a
3 files changed
+168

No files matched your search

+6
View File
@@ -5079,6 +5079,12 @@ the string 'str1' by the string 'str2' once.
Returns the offset of the replacement or STRING_FAILURE if no replacement
was performed.
##### size\_t string\_replace\_all\_str (string\_t v, const char str1[], const char str2[])
##### size\_t string\_replace\_all (string\_t v, const string\_t str1, const string\_t str2)
Replace in the string 'v' all the occurences of
the string 'str1' by the string 'str2'.
##### void string\_replace\_at (string\_t v, size\_t pos, size\_t len, const char str2[])
Replace in the string 'v' the sub-string defined as starting from 'pos' and
+137
View File
@@ -772,6 +772,143 @@ string_replace_at (string_t v, size_t pos, size_t len, const char str2[])
STRINGI_CONTRACT (v);
}
/* Replace all occurences of str1 into str2 when strlen(str1) >= strlen(str2) */
static inline void
stringi_replace_all_str_1ge2 (string_t v, const char str1[], size_t str1len, const char str2[], size_t str2len)
{
STRINGI_CONTRACT (v);
M_ASSERT(str1len >= str2len);
/* str1len < str2len so the string doesn't need to be resized */
size_t vlen = string_size(v);
char *org = stringi_get_str(v);
char *src = org;
char *dst = org;
// Go through all the characters of the string
while (*src != 0) {
// Get a new occurence of str1 in the v string.
char *occ = strstr(src, str1);
if (occ == NULL) {
// No new occurence
break;
}
M_ASSERT(occ >= src);
// Copy the data until the new occurence
if (src != dst) {
memmove(dst, src, (size_t) (occ - src));
}
dst += (occ - src);
src = occ;
// Copy the replaced string
memcpy(dst, str2, str2len);
dst += str2len;
// Advance src pointer
src = occ + str1len;
}
// Finish copying the string until the end
M_ASSERT (src <= org + vlen );
if (src != dst) {
memmove(dst, src, (size_t) (org + vlen + 1 - src) );
}
// Update string size
stringi_set_size(v, (size_t) (dst + vlen - src) );
STRINGI_CONTRACT (v);
}
/* Reverse strstr from the end of the string
org is the start of the string
src is the current character pointer (shall be initialized to the end of the string)
pattern / pattern_size: the pattern to search.
*/
static inline char *
stringi_strstr_r(char org[], char src[], const char pattern[], size_t pattern_size)
{
src -= pattern_size - 1;
while (org <= src) {
if (src[0] == pattern[0]
&& src[pattern_size-1] == pattern[pattern_size-1]
&& memcmp(src, pattern, pattern_size) == 0) {
return src;
}
src --;
}
return NULL;
}
/* Replace all occurences of str1 into str2 when strlen(str1) < strlen(str2) */
static inline void
stringi_replace_all_str_1lo2 (string_t v, const char str1[], size_t str1len, const char str2[], size_t str2len)
{
STRINGI_CONTRACT (v);
M_ASSERT(str1len < str2len);
/* str1len < str2len so the string may need to be resized
Worst case if when v is composed fully of str1 substrings.
Needed size : v.size / str1len * str2len
*/
size_t vlen = string_size(v);
size_t alloc = vlen / str1len * str2len;
stringi_fit2size(v, alloc);
char *org = stringi_get_str(v);
char *src = org + vlen - 1;
char *end = org + string_capacity(v);
char *dst = end;
// Go through all the characters of the string in reverse !
while (src >= org) {
char *occ = stringi_strstr_r(org, src, str1, str1len);
if (occ == NULL) {
break;
}
M_ASSERT(occ + str1len - 1 <= src);
// Copy the data until the new occurence
dst -= (src - (occ + str1len - 1));
memmove(dst, occ+str1len, (size_t) (src - (occ + str1len - 1)));
// Copy the replaced string
dst -= str2len;
memcpy(dst, str2, str2len);
// Advance src pointer
src = occ - 1;
}
// Finish moving data back to their natural place
memmove(src + 1, dst, (size_t) (end - dst) );
// Update string size
vlen = (size_t) (src - org + end - dst + 1);
org[vlen] = 0;
stringi_set_size(v, vlen );
STRINGI_CONTRACT (v);
}
static inline void
string_replace_all_str (string_t v, const char str1[], const char str2[])
{
size_t str1_l = strlen(str1);
size_t str2_l = strlen(str2);
assert(str1_l > 0);
assert(str2_l > 0);
if (str1_l >= str2_l) {
stringi_replace_all_str_1ge2(v, str1, str1_l, str2, str2_l );
} else {
stringi_replace_all_str_1lo2(v, str1, str1_l, str2, str2_l );
}
}
static inline void
string_replace_all (string_t v, const string_t str1, const string_t str2)
{
size_t str1_l = string_size(str1);
size_t str2_l = string_size(str2);
assert(str1_l > 0);
assert(str2_l > 0);
if (str1_l >= str2_l) {
stringi_replace_all_str_1ge2(v, string_get_cstr(str1), str1_l, string_get_cstr(str2), str2_l );
} else {
stringi_replace_all_str_1lo2(v, string_get_cstr(str1), str1_l, string_get_cstr(str2), str2_l );
}
}
/* Format in the string the given printf format */
static inline int
string_printf (string_t v, const char format[], ...)
+25
View File
@@ -217,6 +217,31 @@ static void test0(void)
assert (i != STRING_FAILURE);
assert (string_cmp_str (s1, "Hello, Juliette!") == 0);
string_set_str(s1, "Hello world 4 life world is real another world");
string_replace_all_str(s1, "world", "earth");
assert( string_equal_str_p(s1, "Hello earth 4 life earth is real another earth"));
string_set_str(s1, "Hello world 4 life world is real another world");
string_replace_all_str(s1, "world", "Wrld");
assert( string_equal_str_p(s1, "Hello Wrld 4 life Wrld is real another Wrld"));
string_set_str(s1, "world Hello world 4 life world is real another planet");
string_replace_all_str(s1, "world", "Wrld");
assert( string_equal_str_p(s1, "Wrld Hello Wrld 4 life Wrld is real another planet"));
string_set_str(s1, "Hello world 4 life world is real another world");
string_replace_all_str(s1, "world", "**WORLD**");
assert( string_equal_str_p(s1, "Hello **WORLD** 4 life **WORLD** is real another **WORLD**"));
string_set_str(s1, "world Hello world 4 life world is real another planet");
string_replace_all_str(s1, "world", "**WORLD**");
assert( string_equal_str_p(s1, "**WORLD** Hello **WORLD** 4 life **WORLD** is real another planet"));
string_set_str(s1, "HELLO");
string_set_str(s2, "WORLD");
string_replace_all(s1, s1, s2);
assert( string_equal_str_p(s1, "WORLD"));
string_printf (s1, "");
assert (string_cmp_str (s1, "") == 0);
assert (string_size (s1) == 0);