From 74d27972dd30cbd3e52824862538cdd2deb27218 Mon Sep 17 00:00:00 2001 From: Juan de Bruin Date: Thu, 30 May 2024 20:33:44 +0200 Subject: [PATCH 1/3] builtin,js: Implement JS `string.split_any` --- vlib/builtin/js/jsfns.js.v | 8 +++++- vlib/builtin/js/string.js.v | 31 +++++++++++++++++++++ vlib/builtin/js/string_test.js.v | 46 ++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/vlib/builtin/js/jsfns.js.v b/vlib/builtin/js/jsfns.js.v index 49c3b38831fde2..5045f30c050dc9 100644 --- a/vlib/builtin/js/jsfns.js.v +++ b/vlib/builtin/js/jsfns.js.v @@ -19,6 +19,12 @@ pub interface JS.Number { JS.Any } +pub interface JS.RegExp { + JS.Any +} + +pub type SplitSeparator = JS.String | JS.RegExp + @[single_impl] pub interface JS.String { JS.Any @@ -32,7 +38,7 @@ pub interface JS.String { endsWith(substr JS.String) JS.Boolean startsWith(substr JS.String) JS.Boolean slice(a JS.Number, b JS.Number) JS.String - split(dot JS.String) JS.Array + split(delim SplitSeparator) JS.Array indexOf(needle JS.String) JS.Number lastIndexOf(needle JS.String) JS.Number } diff --git a/vlib/builtin/js/string.js.v b/vlib/builtin/js/string.js.v index ee9246bb482462..3416d2418db360 100644 --- a/vlib/builtin/js/string.js.v +++ b/vlib/builtin/js/string.js.v @@ -85,6 +85,37 @@ pub fn (s string) split(dot string) []string { return arr } +pub fn (s string) split_any(delim string) []string { + if delim.len == 0 { + return s.split(delim) + } + + mut pattern := delim + + // we use a regex with a bracket expression to match any of the characters in delim + // so we need to prevent the caller from escaping the regex + // to do this we escape any `]`, and remove all `\` while adding an escaped `\\` + // back if the original string contained any + if pattern.contains('\\') { + pattern = pattern.replace('\\', '') + pattern = '${pattern}\\\\' + } + pattern = pattern.replace(']', '\\]') + + mut regexp := JS.RegExp{} + #regexp = new RegExp('[' + pattern.str + ']', 'g') + tmparr := s.str.split(regexp).map(fn (it JS.Any) JS.Any { + res := '' + #res.str = it + return res + }) + _ := tmparr + mut arr := []string{} + #arr = new array(new array_buffer({arr: tmparr,index_start: new int(0),len: new int(tmparr.length)})) + + return arr +} + pub fn (s string) bytes() []u8 { sep := '' tmparr := s.str.split(sep.str).map(fn (it JS.Any) JS.Any { diff --git a/vlib/builtin/js/string_test.js.v b/vlib/builtin/js/string_test.js.v index 7222ec4f443b23..547cfb76e8ad9f 100644 --- a/vlib/builtin/js/string_test.js.v +++ b/vlib/builtin/js/string_test.js.v @@ -232,6 +232,52 @@ fn test_split() { assert vals[1] == '' } +fn test_split_any() { + mut s := 'aaa' + mut a := s.split_any('') + assert a.len == 3 + assert a[0] == 'a' + assert a[1] == 'a' + assert a[2] == 'a' + s = '' + a = s.split_any('') + assert a.len == 0 + s = '12131415' + a = s.split_any('1') + assert a.len == 5 + assert a[0] == '' + assert a[1] == '2' + assert a[2] == '3' + assert a[3] == '4' + assert a[4] == '5' + s = '12131415' + a = s.split_any('2345') + assert a.len == 5 + assert a[0] == '1' + assert a[1] == '1' + assert a[2] == '1' + assert a[3] == '1' + assert a[4] == '' + s = 'a,b,c' + a = s.split_any('],') + assert a.len == 3 + assert a[0] == 'a' + assert a[1] == 'b' + assert a[2] == 'c' + s = 'a]b]c' + a = s.split_any('],') + assert a.len == 3 + assert a[0] == 'a' + assert a[1] == 'b' + assert a[2] == 'c' + s = 'a]b]c' + a = s.split_any('],\\') + assert a.len == 3 + assert a[0] == 'a' + assert a[1] == 'b' + assert a[2] == 'c' +} + /* fn test_trim_space() { a := ' a ' From 0cc019c3f1d78810800bf2f954c46cd926dfc819 Mon Sep 17 00:00:00 2001 From: Juan de Bruin Date: Thu, 30 May 2024 20:43:07 +0200 Subject: [PATCH 2/3] fix formatting --- vlib/builtin/js/jsfns.js.v | 2 +- vlib/builtin/js/string.js.v | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/vlib/builtin/js/jsfns.js.v b/vlib/builtin/js/jsfns.js.v index 5045f30c050dc9..0dd89dba135866 100644 --- a/vlib/builtin/js/jsfns.js.v +++ b/vlib/builtin/js/jsfns.js.v @@ -23,7 +23,7 @@ pub interface JS.RegExp { JS.Any } -pub type SplitSeparator = JS.String | JS.RegExp +pub type SplitSeparator = JS.RegExp | JS.String @[single_impl] pub interface JS.String { diff --git a/vlib/builtin/js/string.js.v b/vlib/builtin/js/string.js.v index 3416d2418db360..d7ec40f539ae6f 100644 --- a/vlib/builtin/js/string.js.v +++ b/vlib/builtin/js/string.js.v @@ -104,9 +104,11 @@ pub fn (s string) split_any(delim string) []string { mut regexp := JS.RegExp{} #regexp = new RegExp('[' + pattern.str + ']', 'g') + tmparr := s.str.split(regexp).map(fn (it JS.Any) JS.Any { res := '' #res.str = it + return res }) _ := tmparr From 90259b9e149ea36d64c2917c714f5061207cc663 Mon Sep 17 00:00:00 2001 From: Juan de Bruin Date: Wed, 5 Jun 2024 14:17:30 +0200 Subject: [PATCH 3/3] jsgen: update split_any to match V backend behavior --- vlib/builtin/js/string.js.v | 7 +++++++ vlib/builtin/js/string_test.js.v | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/vlib/builtin/js/string.js.v b/vlib/builtin/js/string.js.v index d7ec40f539ae6f..7b565eaf81c1f0 100644 --- a/vlib/builtin/js/string.js.v +++ b/vlib/builtin/js/string.js.v @@ -112,9 +112,16 @@ pub fn (s string) split_any(delim string) []string { return res }) _ := tmparr + mut arr := []string{} #arr = new array(new array_buffer({arr: tmparr,index_start: new int(0),len: new int(tmparr.length)})) + // FIXME: ugly hack to handle edge case where the last character in the string is + // one of the delimiters to match V behavior + #if (s.len > 0 && pattern.str.includes(s.str[s.len - 1])) { + arr.pop() + #} + return arr } diff --git a/vlib/builtin/js/string_test.js.v b/vlib/builtin/js/string_test.js.v index 547cfb76e8ad9f..3cbe571d8236cf 100644 --- a/vlib/builtin/js/string_test.js.v +++ b/vlib/builtin/js/string_test.js.v @@ -252,12 +252,11 @@ fn test_split_any() { assert a[4] == '5' s = '12131415' a = s.split_any('2345') - assert a.len == 5 + assert a.len == 4 assert a[0] == '1' assert a[1] == '1' assert a[2] == '1' assert a[3] == '1' - assert a[4] == '' s = 'a,b,c' a = s.split_any('],') assert a.len == 3