From 063c0548b0905959d80dfac6a9a8e51c15e8d8c2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 16 Oct 2020 15:30:14 +0100 Subject: [PATCH] Add new package strings procedures: trim_prefix, trim_suffix, to_valid_utf8 --- core/strings/strings.odin | 69 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/core/strings/strings.odin b/core/strings/strings.odin index cbde2c9c8..c706f5940 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -660,6 +660,19 @@ trim_null :: proc(s: string) -> string { return trim_right_null(trim_left_null(s)); } +trim_prefix :: proc(s, prefix: string) -> string { + if has_prefix(s, prefix) { + return s[len(prefix):]; + } + return s; +} + +trim_suffix :: proc(s, suffix: string) -> string { + if has_suffix(s, suffix) { + return s[:len(s)-len(suffix)]; + } + return s; +} split_multi :: proc(s: string, substrs: []string, skip_empty := false, allocator := context.allocator) -> []string #no_bounds_check { if s == "" || len(substrs) <= 0 { @@ -1106,6 +1119,62 @@ right_justify :: proc(str: string, length: int, pad: string, allocator := contex } + +to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) -> string { + if len(s) == 0 { + return ""; + } + + b := make_builder_len_cap(0, 0, allocator); + + s := s; + for c, i in s { + if c != utf8.RUNE_ERROR { + continue; + } + + _, w := utf8.decode_rune_in_string(s[i:]); + if w == 1 { + grow_builder(&b, len(s) + len(replacement)); + write_string(&b, s[:i]); + s = s[i:]; + break; + } + } + + if builder_cap(b) == 0 { + return clone(s, allocator); + } + + invalid := false; + + for i := 0; i < len(s); /**/ { + c := s[i]; + if c < utf8.RUNE_SELF { + i += 1; + invalid = false; + write_byte(&b, c); + continue; + } + + _, w := utf8.decode_rune_in_string(s[i:]); + if w == 1 { + i += 1; + if !invalid { + invalid = true; + write_string(&b, replacement); + } + continue; + } + invalid = false; + write_string(&b, s[i:][:w]); + i += w; + } + return to_string(b); +} + + + @private write_pad_string :: proc(b: ^Builder, pad: string, pad_len, remains: int) { repeats := remains / pad_len;