aboutsummaryrefslogtreecommitdiff
path: root/core/strings
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2020-07-10 08:25:24 +0100
committerGitHub <noreply@github.com>2020-07-10 08:25:24 +0100
commitf65fa0e4a6201fa7a67c5b0013f460b902550a57 (patch)
treeab244a8e82a81e2bf8c87df72a2555e80a4c6a15 /core/strings
parent65b9dbe13f2749c943c21e7880356b6e6efcfc8b (diff)
parente3d1d1d85c68b6ebc999cae648e55c692e1258d2 (diff)
Merge pull request #339 from dotbmp/master
"core:path" Path library and "core:strings" `split` Utilities
Diffstat (limited to 'core/strings')
-rw-r--r--core/strings/strings.odin150
1 files changed, 150 insertions, 0 deletions
diff --git a/core/strings/strings.odin b/core/strings/strings.odin
index b6af8dc53..32fbcbd20 100644
--- a/core/strings/strings.odin
+++ b/core/strings/strings.odin
@@ -641,6 +641,7 @@ trim_space :: proc(s: string) -> string {
return trim_right_space(trim_left_space(s));
}
+
trim_left_null :: proc(s: string) -> string {
return trim_left_proc(s, is_null);
}
@@ -653,6 +654,155 @@ trim_null :: proc(s: string) -> string {
return trim_right_null(trim_left_null(s));
}
+
+// returns a slice of sub-strings into `s`
+// `allocator` is used only for the slice
+// `skip_empty=true` does not return zero-length substrings
+split :: proc{split_single, split_multi};
+
+split_single :: proc(s, substr: string, skip_empty := false, allocator := context.temp_allocator) -> []string #no_bounds_check {
+ if s == "" || substr == "" do return nil;
+
+ sublen := len(substr);
+ shared := len(s) - sublen;
+
+ if shared <= 0 {
+ return nil;
+ }
+
+ // number, index, last
+ n, i, l := 0, 0, 0;
+
+ // count results
+ first_pass: for i <= shared {
+ if s[i:i+sublen] == substr {
+ if !skip_empty || i - l > 0 {
+ n += 1;
+ }
+
+ i += sublen;
+ l = i;
+ } else {
+ _, skip := utf8.decode_rune_in_string(s[i:]);
+ i += skip;
+ }
+ }
+
+ if !skip_empty || len(s) - l > 0 {
+ n += 1;
+ }
+
+ if n < 1 {
+ // no results
+ return nil;
+ }
+
+ buf := make([]string, n, allocator);
+
+ n, i, l = 0, 0, 0;
+
+ // slice results
+ second_pass: for i <= shared {
+ if s[i:i+sublen] == substr {
+ if !skip_empty || i - l > 0 {
+ buf[n] = s[l:i];
+ n += 1;
+ }
+
+ i += sublen;
+ l = i;
+ } else {
+ _, skip := utf8.decode_rune_in_string(s[i:]);
+ i += skip;
+ }
+ }
+
+ if !skip_empty || len(s) - l > 0 {
+ buf[n] = s[l:];
+ }
+
+ return buf;
+}
+
+split_multi :: proc(s: string, substrs: []string, skip_empty := false, allocator := context.temp_allocator) -> []string #no_bounds_check {
+ if s == "" || len(substrs) <= 0 {
+ return nil;
+ }
+
+ sublen := len(substrs[0]);
+
+ for substr in substrs[1:] {
+ sublen = min(sublen, len(substr));
+ }
+
+ shared := len(s) - sublen;
+
+ if shared <= 0 {
+ return nil;
+ }
+
+ // number, index, last
+ n, i, l := 0, 0, 0;
+
+ // count results
+ first_pass: for i <= shared {
+ for substr in substrs {
+ if s[i:i+sublen] == substr {
+ if !skip_empty || i - l > 0 {
+ n += 1;
+ }
+
+ i += sublen;
+ l = i;
+
+ continue first_pass;
+ }
+ }
+
+ _, skip := utf8.decode_rune_in_string(s[i:]);
+ i += skip;
+ }
+
+ if !skip_empty || len(s) - l > 0 {
+ n += 1;
+ }
+
+ if n < 1 {
+ // no results
+ return nil;
+ }
+
+ buf := make([]string, n, allocator);
+
+ n, i, l = 0, 0, 0;
+
+ // slice results
+ second_pass: for i <= shared {
+ for substr in substrs {
+ if s[i:i+sublen] == substr {
+ if !skip_empty || i - l > 0 {
+ buf[n] = s[l:i];
+ n += 1;
+ }
+
+ i += sublen;
+ l = i;
+
+ continue second_pass;
+ }
+ }
+
+ _, skip := utf8.decode_rune_in_string(s[i:]);
+ i += skip;
+ }
+
+ if !skip_empty || len(s) - l > 0 {
+ buf[n] = s[l:];
+ }
+
+ return buf;
+}
+
// scrub scruvs invalid utf-8 characters and replaces them with the replacement string
// Adjacent invalid bytes are only replaced once
scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> string {