Skip to content

Instantly share code, notes, and snippets.

@poseidon4o
Created February 15, 2023 13:40
Show Gist options
  • Save poseidon4o/4f26a5a4b49c78c2806935206ee23ee4 to your computer and use it in GitHub Desktop.
Save poseidon4o/4f26a5a4b49c78c2806935206ee23ee4 to your computer and use it in GitHub Desktop.
#include <iostream>
/**
* @brief Compute the length of a string (number of bytes before \0)
*
*/
int getStrlen(const char *str) {
// library function:
// return strlen(str);
int length = 0;
while(*str) {
++str;
++length;
}
return length;
}
/**
* @brief Copy string into destination up-to @count bytes
*
* @param destination - pointer to the destination of the copy
* @param source - the source string to copy from
* @param count - upper limit of bytes to copy
*/
void copyString(char *destination, const char *source, int count) {
// library function:
// strncpy(destination, source, count); return;
for (int c = 0; c < count && *source; c++) {
*destination = *source;
++destination;
++source;
}
}
/**
* @brief Compare two strings for equality
*
*/
bool compareString(const char *a, const char *b) {
// library function:
// return strcmp(a, b) == 0;
while (*a && *b) {
if (*a != *b) {
return false;
}
++a;
++b;
}
return *a == *b;
}
/**
* @brief Compare two string for equality up to maximum bytes
*
* @param a LHS of comparison
* @param b RHS of comparison
* @param count max bytes to compare
*/
bool compareSubString(const char *a, const char *b, int count) {
// library function:
// return strncmp(a, b, count) == 0;
while (*a && *b && count > 0) {
if (*a != *b) {
return false;
}
++a;
++b;
--count;
}
return count == 0;
}
/**
* @brief Extract substring and insert into array of strings at specific index
*
* @param start The start of the substring to extract
* @param end The end of the substring to extract (points one after the last symbol)
* @param result The array to append the new string to
* @param index The index in @result at which to append at
*/
void newSubString(const char *start, const char *end, char **&result, int &index) {
const int allocateSize = end - start + 1;
char *word = new (std::nothrow) char[allocateSize];
if (!word) {
for (int c = 0; c < index; c++) {
delete[] result[c];
}
delete[] result;
result = nullptr;
}
copyString(word, start, allocateSize - 1);
word[allocateSize - 1] = '\0';
result[index++] = word;
}
/**
* @brief Split a string by delimiter and return array of newly allocate parts. If @result is nullptr
* computes the number of elements that it needs to have.
*
* @param string The string to split
* @param delimiter The delimiter to split at
* @param keepEmpty If true, empty substring will be returned in @result, otherwise it will not contain empty strings
* @param result The output parameter, can be nullptr to compute its required size
* @return int The number of elements in @result
*/
int stringSplitSub(const char *string, const char *delimiter, bool keepEmpty, char **&result) {
const char *iter = string;
const char *start = iter;
const char *end = nullptr;
const int delimiterSize = getStrlen(delimiter);
int count = 0;
while (*iter) {
if (compareSubString(iter, delimiter, delimiterSize)) {
end = iter;
iter += delimiterSize;
if (keepEmpty || (end - start) > 0) {
if (!result) {
++count;
} else {
newSubString(start, end, result, count);
}
}
start = iter;
} else {
++iter;
}
}
if (result) {
end = iter;
if (keepEmpty || (end - start) > 0) {
newSubString(start, end, result, count);
}
result[count++] = nullptr;
} else {
++count;
}
return count;
}
char ** stringSplit(const char *string, const char *delimiter, bool keepEmpty) {
char ** result = nullptr;
const int count = stringSplitSub(string, delimiter, keepEmpty, result);
result = new (std::nothrow) char*[count + 1];
if (!result) {
return nullptr;
}
stringSplitSub(string, delimiter, keepEmpty, result);
return result;
}
char *stringReplace(const char *haystack, const char *needle, const char *replace) {
int occurrences = 0;
const char *iter = haystack;
const int needleSize = getStrlen(needle);
while (*iter) {
if (compareSubString(iter, needle, needleSize)) {
iter += needleSize;
++occurrences;
} else {
++iter;
}
}
const int replaceSize = getStrlen(replace);
const int diff = (replaceSize - needleSize) * occurrences;
const int haystackSize = iter - haystack;
const int resultSize = haystackSize + diff;
char *result = new (std::nothrow) char[resultSize + 1];
if (!result) {
return nullptr;
}
iter = haystack;
char *output = result;
while (*iter) {
if (compareSubString(iter, needle, needleSize)) {
iter += needleSize;
copyString(output, replace, replaceSize);
output += replaceSize;
} else {
*output = *iter;
++iter;
++output;
}
}
*output = '\0';
return result;
}
/**
* @brief Compare if two string arrays contain the same strings in the same order
*
*/
void compareStringArray(char **a, const char **b) {
std::cout << "\texp: {";
for (int c = 0; b[c]; c++) {
std::cout << "[" << b[c] << "] ";
}
std::cout << "}\n";
std::cout << "\tgot: {";
for (int c = 0; a[c]; c++) {
std::cout << "[" << a[c] << "] ";
}
std::cout << "}\n";
int index = 0;
bool allSame = true;
while (a[index] && b[index]) {
if (!compareString(a[index], b[index])) {
allSame = false;
}
++index;
}
if (a[index] != b[index]) {
allSame = false;
}
std::cout << (allSame ? "SUCCESS\n" : "FAIL\n");
}
#define checkSplit(string, delimiter, flag, ...) \
do { \
const char *_ex[] = {__VA_ARGS__}; \
std::cout << "string (" << string << "), delimiter (" << delimiter << ")\n"; \
char **result = stringSplit(string, delimiter, flag); \
compareStringArray(result, _ex); \
char **iter = result; \
while(*iter) delete[] *iter++; \
delete[] result; \
} while(false)
#define checkReplace(string, needle, replace, expected) \
do { \
char *replaced = stringReplace(string, needle, replace); \
std::cout << "stringReplace(\"" << string << "\", \"" << needle << "\", \"" << replace << "\")\n"; \
std::cout << "\texp: [" << expected << "]\n"; \
std::cout << "\tgot: [" << replaced << "]\n"; \
std::cout << "" << (compareString(replaced, expected) ? "SUCCESS" : "FAIL") << "\n"; \
delete[] replaced; \
} while(false)
int main() {
checkSplit("ABA", "A", true, "", "B", "", nullptr);
checkSplit("ABA", "A", false, "B", nullptr);
checkSplit(" t ", " ", true, "", "", "t", "", "", nullptr);
checkSplit(" t ", " ", true, "", "t", "", nullptr);
checkSplit(" t ", " ", false, "t", nullptr);
checkReplace("jump over", " ", "!", "jump!over");
checkReplace("jump over", " ", "<SPACE>", "jump<SPACE>over");
checkReplace("aaaaaaaaa", "a", "bbbbbbbbbbbb", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
checkReplace("aaaaaaaaa", "a", "", "");
checkReplace("jump<SPACE>over", "<SPACE>", " ", "jump over");
checkReplace("the quick brown fox jumps over the brown fence"," ", "<SPACE>", "the<SPACE>quick<SPACE>brown<SPACE>fox<SPACE>jumps<SPACE>over<SPACE>the<SPACE>brown<SPACE>fence");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment