From 0dc900ba346d62d6aced60a6d3d06b6a8df96d60 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sun, 1 Aug 2021 19:41:20 +0200 Subject: Add `strings.cut`, which returns a substring. --- core/strings/strings.odin | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) 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_; -- cgit v1.2.3 From d260ca6738f1122d2e1767038afb148442dbdb7b Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 2 Aug 2021 17:58:42 +0200 Subject: string.cut uses context.allocator by default. --- core/strings/strings.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 397b14b7c..6d135fc75 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -169,12 +169,12 @@ concatenate :: proc(a: []string, allocator := context.allocator) -> string { `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) { +cut :: proc(s: string, rune_offset := int(0), rune_length := int(0), allocator := context.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 { + if rune_offset == 0 && rune_length <= 0 { return clone(s, allocator); } if rune_length == 0 { rune_length = l; } -- cgit v1.2.3