Created
February 15, 2023 13:40
-
-
Save poseidon4o/4f26a5a4b49c78c2806935206ee23ee4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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