Browse Source

Merge pull request #1065 from Kelimion/string_cut

Add `strings.cut`, which returns a substring.
Jeroen van Rijn 4 years ago
parent
commit
c0f746a251
1 changed files with 34 additions and 0 deletions
  1. 34 0
      core/strings/strings.odin

+ 34 - 0
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.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_;