diff --git a/docs/docs/strings.md b/docs/docs/strings.md index 5dfb75c84..bc4520af3 100644 --- a/docs/docs/strings.md +++ b/docs/docs/strings.md @@ -205,6 +205,15 @@ To find the index of a given substring, use the `.find()` method. This method ta "House".find("Lost Keys"); // -1 (Not found) ``` +### string.findLast(String) -> Number + +Returns the last index of the given string. If the substring doesn't exist, -1 is returned. + +```cs +"woolly woolly mammoth".findLast("woolly"); // 7 +"mammoth".findLast("woolly"); // -1 +``` + ### string.leftStrip() -> String Strips whitespace from the left side of a string and returns the result. diff --git a/src/vm/datatypes/strings.c b/src/vm/datatypes/strings.c index 296084e03..297ca0103 100644 --- a/src/vm/datatypes/strings.c +++ b/src/vm/datatypes/strings.c @@ -275,6 +275,49 @@ static Value findString(DictuVM *vm, int argCount, Value *args) { return NUMBER_VAL(position); } +static Value findLastString(DictuVM *vm, int argCount, Value *args) { + if (argCount != 1) { + runtimeError(vm, "findLast() takes 1 argument (%d given)", argCount); + return EMPTY_VAL; + } + + const char *str = AS_CSTRING(args[0]); + const char *ss = AS_CSTRING(args[1]); + const char *p = str; + int found = !*ss; + + if (!found) { + while (*p) { + ++p; + } + + const char *q = ss; + while (*q) { + ++q; + } + + while (!found && !(p-str < q-ss)) { + const char *s = p; + const char *t = q; + + while (t != ss && *(s-1) == *(t-1)) { + --s; + --t; + } + + found = t == ss; + + if (found) { + p = s; + } else { + --p; + } + } + } + + return NUMBER_VAL(found ? p-str : -1); +} + static Value replaceString(DictuVM *vm, int argCount, Value *args) { if (argCount != 2) { runtimeError(vm, "replace() takes 2 arguments (%d given)", argCount); @@ -562,6 +605,7 @@ void declareStringMethods(DictuVM *vm) { defineNative(vm, &vm->stringMethods, "split", splitString); defineNative(vm, &vm->stringMethods, "contains", containsString); defineNative(vm, &vm->stringMethods, "find", findString); + defineNative(vm, &vm->stringMethods, "findLast", findLastString); defineNative(vm, &vm->stringMethods, "replace", replaceString); defineNative(vm, &vm->stringMethods, "lower", lowerString); defineNative(vm, &vm->stringMethods, "upper", upperString); diff --git a/tests/strings/findLast.du b/tests/strings/findLast.du new file mode 100644 index 000000000..1f7d04ea1 --- /dev/null +++ b/tests/strings/findLast.du @@ -0,0 +1,17 @@ +/** + * findLast.du + * + * Testing the str.findLast() method + * + * .findLast() returns the last index of the given string + */ +from UnitTest import UnitTest; + +class TestStringLastIndexOf < UnitTest { + testStringLower() { + this.assertEquals("woolly woolly mammoth".findLast("woolly"), 7); + this.assertEquals("mammoth".findLast("woolly"), -1); + } +} + +TestStringLastIndexOf().run(); \ No newline at end of file diff --git a/tests/strings/import.du b/tests/strings/import.du index 151d47456..624c70e2a 100644 --- a/tests/strings/import.du +++ b/tests/strings/import.du @@ -12,6 +12,7 @@ import "concat.du"; import "startsWith.du"; import "endsWith.du"; import "find.du"; +import "findLast.du"; import "contains.du"; import "strip.du"; import "format.du";