aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2021-08-01 19:41:20 +0200
committerJeroen van Rijn <Kelimion@users.noreply.github.com>2021-08-01 19:41:20 +0200
commit0dc900ba346d62d6aced60a6d3d06b6a8df96d60 (patch)
tree2351d9ac64ce89c15693c5a14b51fc1386de478d
parent700624119beb5ebf6b9ec4e16ece2ba455c7cae1 (diff)
Add `strings.cut`, which returns a substring.
-rw-r--r--core/strings/strings.odin34
1 files changed, 34 insertions, 0 deletions
diff --git a/core/strings/strings.odin b/core/strings/strings.odin
index e81b41222..397b14b7c 100644
--- a/core/strings/strings.odin
+++ b/core/strings/strings.odin
@@ -165,6 +165,40 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string {
return string(b);
}
+/*
+ `rune_offset` and `rune_length` are in runes, not bytes.
+ If `rune_length` <= 0, then it'll return the remainder of the string starting with `rune_offset`.
+*/
+cut :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.temp_allocator) -> (res: string) {
+ s := s; rune_length := rune_length;
+ l := utf8.rune_count_in_string(s);
+
+ if rune_offset >= l { return ""; }
+ if rune_offset == 0 && rune_length == 0 {
+ return clone(s, allocator);
+ }
+ if rune_length == 0 { rune_length = l; }
+
+ bytes_needed := min(rune_length * 4, len(s));
+ buf := make([]u8, bytes_needed, allocator);
+
+ byte_offset := 0;
+ for i := 0; i < l; i += 1 {
+ _, w := utf8.decode_rune_in_string(s);
+ if i >= rune_offset {
+ for j := 0; j < w; j += 1 {
+ buf[byte_offset+j] = s[j];
+ }
+ byte_offset += w;
+ }
+ if rune_length > 0 {
+ if i == rune_offset + rune_length - 1 { break; }
+ }
+ s = s[w:];
+ }
+ return string(buf[:byte_offset]);
+}
+
@private
_split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocator) -> []string {
s, n := s_, n_;