Compare commits

...

1 Commits

Author SHA1 Message Date
d21e942bdf feat(ustring): 实现查找、替换及格式化对齐功能 2026-05-19 18:17:14 +08:00
7 changed files with 376 additions and 39 deletions

View File

@ -53,6 +53,13 @@ int binary_search(const void* key, const void* base, size_t count, size_t obj_si
int binary_search_right(const void* key, const void* base, size_t count, size_t obj_size, compare_fun_t cmp);
// 字符串查找算法
// 1. 暴力查找
int brute_find(const void* key, size_t key_count, const void* base, size_t base_count, size_t obj_size, compare_fun_t cmp);
// 2. KMP查找
int kmp_find(const void* key, size_t key_count, const void* base, size_t base_count, size_t obj_size, compare_fun_t cmp);
#ifdef UNICSTL_ALGO_ENABLE
#ifdef UNICSTL_ALGO_SORT

View File

@ -21,6 +21,7 @@
// clang-format on
typedef enum{
UV_NONE = 0,
UV_CSTR,
UV_CHAR,
UV_USTRING,
@ -71,20 +72,23 @@ struct _ustring
size_t (*count)(struct _ustring *self, const void *obj); // O(nlogn) if sorted; O(n) if not sorted
// -------------------- uview --------------------
// erase
bool (*erase)(struct _ustring *self, ssize_t index, size_t count);
// append
bool (*append)(struct _ustring *self, uview_t newstr);
bool (*insert)(struct _ustring *self, size_t index, uview_t newstr);
bool (*insert)(struct _ustring *self, ssize_t index, uview_t newstr);
// find and ...
ssize_t (*find)(struct _ustring *str, uview_t v);
uview_t (*find)(struct _ustring *self, uview_t v);
bool (*replace)(struct _ustring *self, uview_t oldstr, uview_t newstr);
bool (*remove)(struct _ustring *self, uview_t oldstr);
// split
struct _ustring *(*substr)(struct _ustring *self, size_t start, size_t end);
bool (*split)(struct _ustring *self, uview_t delim);
bool (*splitlines)(struct _ustring *self);
bool (*join)(struct _ustring *self, uview_t delim);
struct _ustring *(*substr)(struct _ustring *self, ssize_t start, ssize_t end);
// bool (*split)(struct _ustring *self, uview_t delim);
// bool (*splitlines)(struct _ustring *self);
// bool (*join)(struct _ustring *self, uview_t delim);
// judge
bool (*isdigit)(struct _ustring *self);
@ -113,7 +117,6 @@ struct _ustring
bool (*ljust)(struct _ustring *self, size_t width);
bool (*rjust)(struct _ustring *self, size_t width);
bool (*center)(struct _ustring *self, size_t width);
bool (*format)(struct _ustring *self, const char *format);
// compare
int (*eq)(struct _ustring *self, uview_t v);

View File

@ -128,7 +128,6 @@ bool counting_sort(void* base, size_t count, size_t obj_size)
return false;
}
int linear_search(const void* key, const void* base, size_t count, size_t obj_size, compare_fun_t cmp)
{
if (key == NULL)
@ -146,14 +145,22 @@ int linear_search(const void* key, const void* base, size_t count, size_t obj_si
return -1;
}
// 2. 二分查找(默认左边界)
int binary_search(const void* key, const void* base, size_t count, size_t obj_size, compare_fun_t cmp)
{
}
// 3. 二分找右边界:右边界
int binary_search_right(const void* key, const void* base, size_t count, size_t obj_size, compare_fun_t cmp)
{
}
int brute_find(const void* key, size_t key_count, const void* base, size_t base_count, size_t obj_size, compare_fun_t cmp)
{
}
int kmp_find(const void* key, size_t key_count, const void* base, size_t base_count, size_t obj_size, compare_fun_t cmp)
{
}

View File

@ -171,7 +171,7 @@ bool darray_erase(struct _darray *self, size_t index, size_t count)
{
return false;
}
if (count > self->size(self) - index)
if (index + count > self->size(self))
{
count = self->size(self) - index;
}

View File

@ -13,6 +13,7 @@
#include <ctype.h>
static const char null_char = '\0';
static const char space_char = ' ';
static size_t ustring_len(struct _ustring *self)
{
@ -90,7 +91,25 @@ static bool ustring_resize(struct _ustring *self, size_t size)
return true;
}
static bool ustring_insert(struct _ustring *self, size_t index, uview_t v)
static bool ustring_erase(struct _ustring *self, ssize_t index, size_t count)
{
unicstl_assert(self != NULL);
unicstl_assert(self->_alist != NULL);
log_debug("erase start");
if(index >= (ssize_t)self->len(self))
{
log_error("index or count error");
return false;
}
if(index + count > (ssize_t)self->len(self))
{
count = self->len(self) - index;
}
log_debug("index = %d, count = %d", index, count);
return self->_alist->erase(self->_alist, index, count);
}
static bool ustring_insert(struct _ustring *self, ssize_t index, uview_t v)
{
unicstl_assert(self != NULL);
unicstl_assert(self->_alist != NULL);
@ -100,30 +119,36 @@ static bool ustring_insert(struct _ustring *self, size_t index, uview_t v)
if (!self->resize(self, len_sum))
{
log_error("resize error");
return false;
}
log_debug("insert str: %s", v.str);
size_t left = len_cur - index;
size_t idx = 0;
ssize_t idx = 0;
char temp = 0;
for (size_t i = 0; i < left; i++)
{
idx = len_cur - 1 - i;
idx = (ssize_t)len_cur - 1 - i;
// log_debug("idx = %d", idx);
if (!self->get(self, idx, &temp))
{
log_error("get ustring[i] error");
return false;
}
idx = len_sum - 1 - i;
idx = (ssize_t)len_sum - 1 - i;
// log_debug("idx = %d", idx);
if (!self->set(self, idx, &temp))
{
log_error("get ustring[i-1] error");
return false;
}
}
// log_debug("move after index");
for (size_t i = 0; i < v.len; i++)
for (ssize_t i = 0; i < v.len; i++)
{
if (!self->set(self, index + i, &v.str[i]))
{
@ -131,6 +156,7 @@ static bool ustring_insert(struct _ustring *self, size_t index, uview_t v)
return false;
}
}
// log_debug("set before index");
if (!self->set(self, len_sum, &null_char))
{
@ -140,10 +166,63 @@ static bool ustring_insert(struct _ustring *self, size_t index, uview_t v)
return true;
}
uview_t ustring_find(struct _ustring *self, uview_t uvstr)
{
unicstl_assert(self != NULL);
unicstl_assert(self->_alist != NULL);
uview_t v = {0, 0, UV_NONE};
v.str = strstr(self->cstr(self), uvstr.str);
if(v.str != NULL)
{
v.len = uvstr.len;
}
return v;
}
bool ustring_replace(struct _ustring *self, uview_t oldstr, uview_t newstr)
{
unicstl_assert(self != NULL);
unicstl_assert(self->_alist != NULL);
uview_t v = self->find(self, oldstr);
if(v.len == 0)
{
log_error("not found");
return false;
}
size_t index = v.str - self->at(self, 0);
if(!self->erase(self, index, oldstr.len))
{
log_error("erase error");
return false;
}
if(!self->insert(self, index, newstr))
{
log_error("insert error");
return false;
}
return true;
}
static bool ustring_remove(struct _ustring *self, uview_t oldstr)
{
unicstl_assert(self != NULL);
unicstl_assert(self->_alist != NULL);
uview_t v = self->find(self, oldstr);
if(v.len == 0)
{
log_error("not found");
return false;
}
size_t index = v.str - self->at(self, 0);
log_debug("remove_idx: %ld", index);
if(!self->erase(self, index, oldstr.len))
{
log_error("erase error");
return false;
}
log_debug("remove ok!");
return true;
}
@ -566,20 +645,116 @@ static bool ustring_strip_right(struct _ustring *self)
return true;
}
bool ustring_ljust(struct _ustring *self, size_t width)
{
unicstl_assert(self != NULL);
if (width <= self->len(self))
{
return true;
}
size_t len = width - self->len(self);
for (size_t i = 0; i < len; i++)
{
self->append(self, uv(" "));
}
return true;
}
static bool ustring_rshift(struct _ustring *self, size_t shift, size_t count)
{
unicstl_assert(self != NULL);
unicstl_assert(self->_alist != NULL);
if(shift + count > self->len(self))
{
if(!self->resize(self, shift + count))
{
return false;
}
}
char* src = (char*)self->at(self, 0);
char* dst = src + shift;
memmove(dst, src, count);
return true;
}
bool ustring_rjust(struct _ustring *self, size_t width)
{
unicstl_assert(self != NULL);
size_t count = self->len(self);
if(width < count)
{
return false;
}
if(!self->resize(self, width))
{
return false;
}
size_t shift = width - count;
if(!ustring_rshift(self, shift, count))
{
log_error("rshift failed");
return false;
}
for(size_t i = 0; i < shift; i++)
{
if(!self->set(self, i, &space_char))
{
log_error("set failed");
return false;
}
}
return true;
}
bool ustring_center(struct _ustring *self, size_t width)
{
unicstl_assert(self != NULL);
size_t count = self->len(self);
if(width < count)
{
return false;
}
if(!self->resize(self, width))
{
return false;
}
size_t shift = (width - count)/2;
log_debug("space_cnt: %ld", shift);
if(!ustring_rshift(self, shift, count))
{
log_error("rshift failed");
return false;
}
for(size_t i = 0; i < shift; i++)
{
if(!self->set(self, i, &space_char))
{
log_error("insert failed");
return false;
}
}
size_t idx = shift + count;
if((width - count) % 2 == 1)
{
shift += 1;
}
for(size_t i = 0; i < shift; i++)
{
if(!self->set(self, idx + i, &space_char))
{
log_error("insert failed");
return false;
}
}
return true;
}
int ustring_cmp(struct _ustring *self, uview_t v)
{
unicstl_assert(self != NULL);
// size_t min = self->len(self) < v.len ? self->len(self) : v.len;
// for (size_t i = 0; i < min; i++)
// {
// const char *a = (const char *)self->at(self, i);
// if (*a != v.str[i])
// {
// return *(char*)self->at(self, i) - v.str[i];
// }
// }
log_debug("self[%d]:%s, v.str[%d]:%s", self->len(self), self->at(self, 0), v.len, v.str);
size_t max = self->len(self) > v.len ? self->len(self) : v.len;
return strncmp(self->at(self, 0), v.str, max);
}
@ -620,6 +795,34 @@ int ustring_ge(struct _ustring *self, uview_t v)
return self->cmp(self, v) >= 0;
}
struct _ustring* ustring_substr(struct _ustring *self, ssize_t start, ssize_t end)
{
unicstl_assert(self != NULL);
log_debug("substr");
ustring_t substr = ustring_new(uv(""));
if(substr == NULL)
{
return NULL;
}
log_debug("ustring_new");
char ch = 0;
for(ssize_t i = start; i <= end; i++)
{
if(!self->get(self, i, &ch))
{
log_error("get failed");
return NULL;
}
log_debug("ch: %c", ch);
if(!substr->append(substr, uvch(ch)))
{
log_error("append failed");
return NULL;
}
}
return substr;
}
static bool ustring_init(struct _ustring *self, uview_t view, bool is_view)
{
unicstl_assert(self != NULL);
@ -633,11 +836,6 @@ static bool ustring_init(struct _ustring *self, uview_t view, bool is_view)
self->is_view = is_view;
// -------------------- public --------------------
// kernel
self->insert = ustring_insert;
self->remove = ustring_remove;
self->append = ustring_append;
self->set = ustring_set;
self->get = ustring_get;
self->at = ustring_at;
@ -654,6 +852,18 @@ static bool ustring_init(struct _ustring *self, uview_t view, bool is_view)
// iter
self->iter = ustring_iter;
//
self->erase = ustring_erase;
// append
self->append = ustring_append;
self->insert = ustring_insert;
//
self->find = ustring_find;
self->replace = ustring_replace;
self->remove = ustring_remove;
// sort and search
self->index = ustring_index;
self->contains = ustring_contains;
@ -683,6 +893,9 @@ static bool ustring_init(struct _ustring *self, uview_t view, bool is_view)
self->strip = ustring_strip;
self->strip_left = ustring_strip_left;
self->strip_right = ustring_strip_right;
self->ljust = ustring_ljust;
self->rjust = ustring_rjust;
self->center = ustring_center;
self->eq = ustring_eq;
self->ne = ustring_ne;
@ -692,6 +905,11 @@ static bool ustring_init(struct _ustring *self, uview_t view, bool is_view)
self->ge = ustring_ge;
self->cmp = ustring_cmp;
// split
self->substr = ustring_substr;
// self->split = ustring_split;
// self->join = ustring_join;
// -------------------- default --------------------
self->print_obj = uprint_char;

View File

@ -24,11 +24,11 @@
#define UNITTEST_LINKLIST (UNITTEST_ALL || 0)
#define UNITTEST_DLINKLIST (UNITTEST_ALL || 0)
#define UNITTEST_DARRAY (UNITTEST_ALL || 1)
#define UNITTEST_DARRAY (UNITTEST_ALL || 0)
#define UNITTEST_RINGBUF (UNITTEST_ALL || 0)
#define UNITTEST_RAWBUF (UNITTEST_ALL || 0)
#define UNITTEST_ARRAYLIST (UNITTEST_ALL || 1)
#define UNITTEST_ARRAYLIST (UNITTEST_ALL || 0)
#define UNITTEST_DEQUE (UNITTEST_ALL || 0)
#define UNITTEST_QUEUE (UNITTEST_ALL || 0)

View File

@ -100,9 +100,9 @@ void test_ustring_set(void)
void test_ustring_tolower(void)
{
ustring_t str = ustring_new(uv("HELLO wolrD"));
ustring_t str = ustring_new(uv("HELLO worlD"));
str->tolower(str);
TEST_ASSERT_EQUAL_STRING("hello wolrd", str->cstr(str));
TEST_ASSERT_EQUAL_STRING("hello world", str->cstr(str));
ustring_free(&str);
}
@ -273,6 +273,48 @@ void test_ustring_strip(void)
ustring_free(&str);
}
void test_ustring_ljust(void)
{
ustring_t str = ustring_new(uv("unicstl"));
TEST_ASSERT_EQUAL_INT(7, str->len(str));
TEST_ASSERT_TRUE(str->ljust(str, 16));
TEST_ASSERT_EQUAL_INT(16, str->len(str));
TEST_ASSERT_EQUAL_STRING("unicstl ", str->cstr(str));
ustring_free(&str);
}
void test_ustring_rjust(void)
{
ustring_t str = ustring_new(uv("unicstl"));
TEST_ASSERT_EQUAL_INT(7, str->len(str));
TEST_ASSERT_TRUE(str->rjust(str, 16));
TEST_ASSERT_EQUAL_INT(16, str->len(str));
TEST_ASSERT_EQUAL_STRING(" unicstl", str->cstr(str));
ustring_free(&str);
}
void test_ustring_center(void)
{
ustring_t str = ustring_new(uv("unicstl"));
TEST_ASSERT_EQUAL_INT(7, str->len(str));
TEST_ASSERT_TRUE(str->center(str, 16));
TEST_ASSERT_EQUAL_INT(16, str->len(str));
TEST_ASSERT_EQUAL_STRING(" unicstl ", str->cstr(str));
ustring_free(&str);
}
void test_ustring_erase(void)
{
log_info("start");
ustring_t str = ustring_new_fromcstr("hello world");
TEST_ASSERT_EQUAL_INT(11, str->len(str));
TEST_ASSERT_TRUE(str->erase(str, 2, 7));
TEST_ASSERT_EQUAL_INT(4, str->len(str));
TEST_ASSERT_EQUAL_STRING("held", str->cstr(str));
ustring_free(&str);
log_info("end");
}
void test_ustring_append(void)
{
ustring_t str = ustring_new_fromcstr("unicstl ");
@ -288,16 +330,57 @@ void test_ustring_append(void)
void test_ustring_insert(void)
{
ustring_t str = ustring_new_fromcstr("hello wolrd");
ustring_t str = ustring_new_fromcstr("hello world");
ustring_t str2 = ustring_new_fromcstr(" unicstl");
size_t len = str->len(str);
size_t len2 = str2->len(str2);
TEST_ASSERT_TRUE(str->insert(str, 5, uvs(str2)));
TEST_ASSERT_EQUAL_INT(len + len2, str->len(str));
TEST_ASSERT_EQUAL_STRING("hello unicstl wolrd", str->cstr(str));
TEST_ASSERT_EQUAL_STRING("hello unicstl world", str->cstr(str));
ustring_free(&str);
ustring_free(&str2);
str = ustring_new_fromcstr("hello world");
TEST_ASSERT_TRUE(str->insert(str, 0, uv("unicstl ")));
TEST_ASSERT_EQUAL_INT(len + 8, str->len(str));
TEST_ASSERT_EQUAL_STRING("unicstl hello world", str->cstr(str));
ustring_free(&str);
log_info("end");
}
void test_ustring_find(void)
{
ustring_t str = ustring_new_fromcstr("hello world");
ustring_t str2 = ustring_new_fromcstr("world");
uview_t v = str->find(str, uvs(str2));
TEST_ASSERT_EQUAL_INT(5, v.len);
TEST_ASSERT_EQUAL_STRING("world", v.str);
v = str->find(str, uv("llo"));
TEST_ASSERT_EQUAL_INT(3, v.len);
// TEST_ASSERT_EQUAL_STRING("llo", v.str); // change test case
TEST_ASSERT_EQUAL_MEMORY("llo", v.str, 3); // is ok!
ustring_free(&str);
ustring_free(&str2);
}
void test_ustring_remove(void)
{
ustring_t str = ustring_new_fromcstr("hello world");
TEST_ASSERT_TRUE(str->remove(str, uv("llo wor")));
TEST_ASSERT_EQUAL_INT(4, str->len(str));
TEST_ASSERT_EQUAL_STRING("held", str->cstr(str));
ustring_free(&str);
}
void test_ustring_replace(void)
{
ustring_t str = ustring_new_fromcstr("hello world!");
TEST_ASSERT_TRUE(str->replace(str, uv("world"), uv("unicstl")));
TEST_ASSERT_EQUAL_STRING("hello unicstl!", str->cstr(str));
ustring_free(&str);
}
void test_ustring_cmp(void)
@ -319,6 +402,15 @@ void test_ustring_cmp(void)
ustring_free(&str);
}
void test_ustring_substr(void)
{
ustring_t str = ustring_new_fromcstr("hello world");
ustring_t substr = str->substr(str, 6, 10);
TEST_ASSERT_EQUAL_STRING("world", substr->cstr(substr));
ustring_free(&substr);
ustring_free(&str);
}
void test_ustring(void)
{
UnitySetTestFile(__FILE__);
@ -352,9 +444,19 @@ void test_ustring(void)
RUN_TEST(test_ustring_strip_right);
RUN_TEST(test_ustring_strip_left);
RUN_TEST(test_ustring_strip);
RUN_TEST(test_ustring_ljust);
RUN_TEST(test_ustring_rjust);
RUN_TEST(test_ustring_center);
RUN_TEST(test_ustring_erase);
RUN_TEST(test_ustring_append);
RUN_TEST(test_ustring_insert);
RUN_TEST(test_ustring_find);
RUN_TEST(test_ustring_remove);
RUN_TEST(test_ustring_replace);
RUN_TEST(test_ustring_cmp);
RUN_TEST(test_ustring_substr);
}