diff --git a/docs/docs/strings.md b/docs/docs/strings.md index 8b8e6cf9..bc946f67 100644 --- a/docs/docs/strings.md +++ b/docs/docs/strings.md @@ -310,3 +310,19 @@ Returns the number of words in the given string. Empty strings are considered fa "This is a sentence".wordCount(); // 4 "This is an even longer sentence".wordCount(); // 6 ``` + +### string.collapseSpaces() -> String + +Returns a string with extraneous whitespace removed. + +```cs +"This is a huge string of a lot of spaces.".collapseSpaces(); // "This is a huge string of a lot of spaces." +``` + +### string.wrap(Number) -> String + +Returns a new string with new lines inserted at the given length. + +```cs +"This is a really really long string that will need to be broken up for whatever reason the caller has determined. Not our business as to why, but we can provide the functionality for them to do so.".wrap(80); +``` diff --git a/src/vm/datatypes/sets.c b/src/vm/datatypes/sets.c index 0b3a3f08..f8907688 100644 --- a/src/vm/datatypes/sets.c +++ b/src/vm/datatypes/sets.c @@ -122,4 +122,3 @@ void declareSetMethods(DictuVM *vm) { defineNative(vm, &vm->setMethods, "containsAll", containsAllSet); defineNative(vm, &vm->setMethods, "toBool", boolNative); // Defined in util } - diff --git a/src/vm/datatypes/strings.c b/src/vm/datatypes/strings.c index 929acdba..e58ca3e6 100644 --- a/src/vm/datatypes/strings.c +++ b/src/vm/datatypes/strings.c @@ -668,6 +668,62 @@ static Value isLowerString(DictuVM *vm, int argCount, Value *args) { return BOOL_VAL(true); } +static Value collapseSpacesString(DictuVM *vm, int argCount, Value *args) { + if (argCount != 0) { + runtimeError(vm, "collapseSpaces() takes no arguments (%d given)", argCount); + return EMPTY_VAL; + } + + ObjString *string = AS_STRING(args[0]); + char *temp = ALLOCATE(vm, char, string->length + 1); + strcpy(temp, string->chars); + + int i, j; + for (i = j = 0; temp[i]; ++i) { + if (!isspace(temp[i]) || (i > 0 && !isspace(temp[i-1]))) { + temp[j++] = temp[i]; + } + } + + temp[j+1] = '\0'; + + if (i != j) { + temp = SHRINK_ARRAY(vm, temp, char, string->length + 1, j + 1); + } + + return OBJ_VAL(takeString(vm, temp, j)); +} + +static Value wrapString(DictuVM *vm, int argCount, Value *args) { + if (argCount != 1) { + runtimeError(vm, "wrap() takes 1 argument (%d given)", argCount); + return EMPTY_VAL; + } + + ObjString *string = AS_STRING(args[0]); + char *temp = ALLOCATE(vm, char, string->length + 1); + + int len = AS_NUMBER(args[1]); + + int last = 0; + int count = 0; + + for (int cur = 0; string->chars[cur] != '\0'; cur++, count++) { + temp[cur] = string->chars[cur]; + + if (isspace(temp[cur])) { + last = cur; + } + + if (count >= len) { + temp[last] = '\n'; + count = 0; + } + } + + return OBJ_VAL(takeString(vm, temp, strlen(temp))); +} + void declareStringMethods(DictuVM *vm) { defineNative(vm, &vm->stringMethods, "len", lenString); defineNative(vm, &vm->stringMethods, "toNumber", toNumberString); @@ -691,5 +747,6 @@ void declareStringMethods(DictuVM *vm) { defineNative(vm, &vm->stringMethods, "repeat", repeatString); defineNative(vm, &vm->stringMethods, "isUpper", isUpperString); defineNative(vm, &vm->stringMethods, "isLower", isLowerString); - + defineNative(vm, &vm->stringMethods, "collapseSpaces", collapseSpacesString); + defineNative(vm, &vm->stringMethods, "wrap", wrapString); } diff --git a/tests/strings/collapseSpaces.du b/tests/strings/collapseSpaces.du new file mode 100644 index 00000000..d885ee3f --- /dev/null +++ b/tests/strings/collapseSpaces.du @@ -0,0 +1,20 @@ +/** + * collapseSpaces.du + * + * Testing the str.collapseSpaces() method + * + * .collapseSpaces() returns a string with extraneous spaces removed. + */ +from UnitTest import UnitTest; + +class TestStringCollapseSpaces < UnitTest { + testStringCollapseSpaces() { + const testString = "This is a huge string of a lot of spaces."; + const expected = "This is a huge string of a lot of spaces."; + const res = testString.collapseSpaces(); + this.assertEquals(res, expected); + this.assertNotEquals(testString, expected); + } +} + +TestStringCollapseSpaces().run(); diff --git a/tests/strings/concat.du b/tests/strings/concat.du index c25a5f76..9518698c 100644 --- a/tests/strings/concat.du +++ b/tests/strings/concat.du @@ -17,4 +17,4 @@ class TestStringConcat < UnitTest { } } -TestStringConcat().run(); \ No newline at end of file +TestStringConcat().run(); diff --git a/tests/strings/import.du b/tests/strings/import.du index 709f74fe..766fc8ec 100644 --- a/tests/strings/import.du +++ b/tests/strings/import.du @@ -29,3 +29,5 @@ import "title.du"; import "isUpper.du"; import "isLower.du"; import "wordCount.du"; +import "collapseSpaces.du"; +import "wrap.du"; diff --git a/tests/strings/wrap.du b/tests/strings/wrap.du new file mode 100644 index 00000000..442b0465 --- /dev/null +++ b/tests/strings/wrap.du @@ -0,0 +1,21 @@ +/** + * wrap.du + * + * Testing the str.wrap() method + * + * .wrap() returns a new string with new lines inserted at the given length. + */ +from UnitTest import UnitTest; + +class TestStringWrap < UnitTest { + const maxLen = 80; + + testStringWrap() { + const testString = "This is a really really long string that will need to be broken up for whatever reason the caller has determined. Not out business as to why, but we can provide the functionality for them to do so."; + const res = testString.wrap(this.maxLen); + const idx = res.find("\n"); + this.assertTruthy(res.find("\n") <= this.maxLen); + } +} + +TestStringWrap().run();