diff --git a/doc/spec.md b/doc/spec.md
index 07285894..37896146 100644
--- a/doc/spec.md
+++ b/doc/spec.md
@@ -175,6 +175,8 @@ reproducibility is paramount, such as build tools.
* [string·lower](#string·lower)
* [string·lstrip](#string·lstrip)
* [string·partition](#string·partition)
+ * [string·removeprefix](#string·removeprefix)
+ * [string·removesuffix](#string·removesuffix)
* [string·replace](#string·replace)
* [string·rfind](#string·rfind)
* [string·rindex](#string·rindex)
@@ -680,6 +682,8 @@ Strings have several built-in methods:
* [`lstrip`](#string·lstrip)
* [`partition`](#string·partition)
* [`replace`](#string·replace)
+* [`removeprefix`](#string·removeprefix)
+* [`removesuffix`](#string·removesuffix)
* [`rfind`](#string·rfind)
* [`rindex`](#string·rindex)
* [`rpartition`](#string·rpartition)
@@ -4026,6 +4030,30 @@ If S does not contain `x`, `partition` returns `(S, "", "")`.
"one/two/three".partition("/") # ("one", "/", "two/three")
```
+
+### string·removeprefix
+
+`S.removeprefix(prefix)` returns a copy of string S with the prefix `prefix`
+removed if S starts with `prefix`, otherwise it returns S.
+
+```python
+"banana".removeprefix("ban") # "ana"
+"banana".removeprefix("foo") # "banana"
+"foofoobar".removeprefix("foo") # "foobar"
+```
+
+
+### string·removesuffix
+
+`S.removesuffix(suffix)` returns a copy of string S with the suffix `suffix`
+removed if S ends with `suffix`, otherwise it returns S.
+
+```python
+"banana".removesuffix("nana") # "ba"
+"banana".removesuffix("foo") # "banana"
+"banana".removesuffix("na") # "bana"
+```
+
### string·replace
diff --git a/starlark/library.go b/starlark/library.go
index cb2c8207..1c801be6 100644
--- a/starlark/library.go
+++ b/starlark/library.go
@@ -123,6 +123,8 @@ var (
"lower": NewBuiltin("lower", string_lower),
"lstrip": NewBuiltin("lstrip", string_strip), // sic
"partition": NewBuiltin("partition", string_partition),
+ "removeprefix": NewBuiltin("removeprefix", string_removefix),
+ "removesuffix": NewBuiltin("removesuffix", string_removefix),
"replace": NewBuiltin("replace", string_replace),
"rfind": NewBuiltin("rfind", string_rfind),
"rindex": NewBuiltin("rindex", string_rindex),
@@ -1889,6 +1891,22 @@ func string_partition(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value,
return tuple, nil
}
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·removeprefix
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·removesuffix
+func string_removefix(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
+ recv := string(b.Receiver().(String))
+ var fix string
+ if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &fix); err != nil {
+ return nil, err
+ }
+ if b.name[len("remove")] == 'p' {
+ recv = strings.TrimPrefix(recv, fix)
+ } else {
+ recv = strings.TrimSuffix(recv, fix)
+ }
+ return String(recv), nil
+}
+
// https://github.com/google/starlark-go/blob/master/doc/spec.md#string·replace
func string_replace(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
recv := string(b.Receiver().(String))
diff --git a/starlark/testdata/string.star b/starlark/testdata/string.star
index b317d1af..1a38d622 100644
--- a/starlark/testdata/string.star
+++ b/starlark/testdata/string.star
@@ -470,3 +470,24 @@ assert.true(not "DŽenan LJubović".istitle())
assert.fails(lambda: "".starts_with, "no .starts_with field.*did you mean .startswith")
assert.fails(lambda: "".StartsWith, "no .StartsWith field.*did you mean .startswith")
assert.fails(lambda: "".fin, "no .fin field.*.did you mean .find")
+
+
+# removesuffix
+assert.eq("Apricot".removesuffix("cot"), "Apri")
+assert.eq("Apricot".removesuffix("Cot"), "Apricot")
+assert.eq("Apricot".removesuffix("t"), "Aprico")
+assert.eq("a".removesuffix(""), "a")
+assert.eq("".removesuffix(""), "")
+assert.eq("".removesuffix("a"), "")
+assert.eq("Apricot".removesuffix("co"), "Apricot")
+assert.eq("Apricotcot".removesuffix("cot"), "Apricot")
+
+# removeprefix
+assert.eq("Apricot".removeprefix("Apr"), "icot")
+assert.eq("Apricot".removeprefix("apr"), "Apricot")
+assert.eq("Apricot".removeprefix("A"), "pricot")
+assert.eq("a".removeprefix(""), "a")
+assert.eq("".removeprefix(""), "")
+assert.eq("".removeprefix("a"), "")
+assert.eq("Apricot".removeprefix("pr"), "Apricot")
+assert.eq("AprApricot".removeprefix("Apr"), "Apricot")
\ No newline at end of file