diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 63eb75df27..823f4220fb 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -1616,8 +1616,32 @@ pub fn (s string) repeat(count int) string { // fields returns a string array of the string split by `\t` and ` ` // Example: assert '\t\tv = v'.fields() == ['', '', 'v', '=', 'v'] pub fn (s string) fields() []string { - // TODO do this in a better way - return s.replace('\t', ' ').split(' ') + mut res := []string{} + mut word_start := 0 + mut word_end := 0 + mut is_in_word := false + mut is_space := false + for i, c in s { + is_space = c in [` `, `\t`, `\n`] + if !is_in_word && !is_space { + word_start = i + is_in_word = true + continue + } + if is_space && is_in_word { + word_end = i + res << s[word_start..word_end] + is_in_word = false + word_end = 0 + word_start = 0 + continue + } + } + if is_in_word && word_start > 0 { + // collect the remainder word at the end + res << s[word_start..s.len] + } + return res } // strip_margin allows multi-line strings to be formatted in a way that removes white-space @@ -1684,31 +1708,8 @@ pub fn (s string) strip_margin_custom(del byte) string { // split_by_whitespace - extract only the non whitespace tokens/words from the given string `s`. // example: ' sss ssss'.split_by_whitespace() => ['sss', 'ssss'] + +[deprecated: 'use string.fields() instead'] pub fn (s string) split_by_whitespace() []string { - mut res := []string{} - mut word_start := 0 - mut word_end := 0 - mut is_in_word := false - mut is_space := false - for i, c in s { - is_space = c in [` `, `\t`, `\n`] - if !is_in_word && !is_space { - word_start = i - is_in_word = true - continue - } - if is_space && is_in_word { - word_end = i - res << s[word_start..word_end] - is_in_word = false - word_end = 0 - word_start = 0 - continue - } - } - if is_in_word && word_start > 0 { - // collect the remainder word at the end - res << s[word_start..s.len] - } - return res + return s.fields() } diff --git a/vlib/builtin/string_test.v b/vlib/builtin/string_test.v index ad7dec5573..66f949d522 100644 --- a/vlib/builtin/string_test.v +++ b/vlib/builtin/string_test.v @@ -1,3 +1,5 @@ +import strings + // Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved. // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. @@ -11,7 +13,7 @@ mut: fn test_add() { mut a := 'a' a += 'b' - assert a==('ab') + assert a == ('ab') a = 'a' for i := 1; i < 1000; i++ { a += 'b' @@ -34,14 +36,14 @@ fn test_ends_with() { } fn test_between() { - s := 'hello [man] how you doing' + s := 'hello [man] how you doing' assert s.find_between('[', ']') == 'man' } fn test_compare() { a := 'Music' b := 'src' - assert b>=(a) + assert b >= (a) } fn test_lt() { @@ -88,7 +90,10 @@ fn test_compare_strings() { fn test_sort() { mut vals := [ - 'arr', 'an', 'a', 'any' + 'arr', + 'an', + 'a', + 'any', ] len := vals.len vals.sort() @@ -101,10 +106,13 @@ fn test_sort() { fn test_sort_reverse() { mut vals := [ - 'arr', 'an', 'a', 'any' + 'arr', + 'an', + 'a', + 'any', ] len := vals.len - vals.sort(b>a) + vals.sort(b > a) assert len == vals.len assert vals[0] == 'a' assert vals[1] == 'an' @@ -113,35 +121,35 @@ fn test_sort_reverse() { } fn test_split_nth() { - a := "1,2,3" - assert (a.split(',').len == 3) - assert (a.split_nth(',', -1).len == 3) - assert (a.split_nth(',', 0).len == 3) - assert (a.split_nth(',', 1).len == 1) - assert (a.split_nth(',', 2).len == 2) - assert (a.split_nth(',', 10).len == 3) - b := "1::2::3" - assert (b.split('::').len == 3) - assert (b.split_nth('::', -1).len == 3) - assert (b.split_nth('::', 0).len == 3) - assert (b.split_nth('::', 1).len == 1) - assert (b.split_nth('::', 2).len == 2) - assert (b.split_nth('::', 10).len == 3) - c := "ABCDEF" + a := '1,2,3' + assert a.split(',').len == 3 + assert a.split_nth(',', -1).len == 3 + assert a.split_nth(',', 0).len == 3 + assert a.split_nth(',', 1).len == 1 + assert a.split_nth(',', 2).len == 2 + assert a.split_nth(',', 10).len == 3 + b := '1::2::3' + assert b.split('::').len == 3 + assert b.split_nth('::', -1).len == 3 + assert b.split_nth('::', 0).len == 3 + assert b.split_nth('::', 1).len == 1 + assert b.split_nth('::', 2).len == 2 + assert b.split_nth('::', 10).len == 3 + c := 'ABCDEF' println(c.split('').len) - assert (c.split('').len == 6) - assert (c.split_nth('', 3).len == 3) - assert (c.split_nth('BC', -1).len == 2) - d := "," - assert (d.split(',').len == 2) - assert (d.split_nth('', 3).len == 1) - assert (d.split_nth(',', -1).len == 2) - assert (d.split_nth(',', 3).len == 2) - e := ",,,0,,,,,a,,b," - assert (e.split(',,').len == 5) - assert (e.split_nth(',,', 3).len == 3) - assert (e.split_nth(',', -1).len == 12) - assert (e.split_nth(',', 3).len == 3) + assert c.split('').len == 6 + assert c.split_nth('', 3).len == 3 + assert c.split_nth('BC', -1).len == 2 + d := ',' + assert d.split(',').len == 2 + assert d.split_nth('', 3).len == 1 + assert d.split_nth(',', -1).len == 2 + assert d.split_nth(',', 3).len == 2 + e := ',,,0,,,,,a,,b,' + assert e.split(',,').len == 5 + assert e.split_nth(',,', 3).len == 3 + assert e.split_nth(',', -1).len == 12 + assert e.split_nth(',', 3).len == 3 } fn test_split_nth_values() { @@ -185,15 +193,15 @@ fn test_split() { s = '2018-01-01z13:01:02' vals = s.split('z') assert vals.len == 2 - assert vals[0] =='2018-01-01' + assert vals[0] == '2018-01-01' assert vals[1] == '13:01:02' // ////////// s = '4627a862c3dec29fb3182a06b8965e0025759e18___1530207969___blue' vals = s.split('___') assert vals.len == 3 - assert vals[0]== '4627a862c3dec29fb3182a06b8965e0025759e18' - assert vals[1]=='1530207969' - assert vals[2]== 'blue' + assert vals[0] == '4627a862c3dec29fb3182a06b8965e0025759e18' + assert vals[1] == '1530207969' + assert vals[2] == 'blue' // ///////// s = 'lalala' vals = s.split('a') @@ -238,16 +246,18 @@ fn main() { } fn test_join() { - mut strings := [ 'a', 'b', 'c' ] + mut strings := ['a', 'b', 'c'] mut s := strings.join(' ') assert s == 'a b c' - strings = ['one + strings = [ + 'one two ', - 'three! -four!'] + 'three! +four!', + ] s = strings.join(' ') assert s.contains('one') && s.contains('two ') && s.contains('four') - empty := []string{len:0} + empty := []string{len: 0} assert empty.join('A') == '' } @@ -265,13 +275,13 @@ fn test_clone() { fn test_replace() { a := 'hello man!' mut b := a.replace('man', 'world') - assert b==('hello world!') + assert b == ('hello world!') b = b.replace('!', '') - assert b==('hello world') + assert b == ('hello world') b = b.replace('h', 'H') - assert b==('Hello world') + assert b == ('Hello world') b = b.replace('foo', 'bar') - assert b==('Hello world') + assert b == ('Hello world') s := 'hey man how are you' assert s.replace('man ', '') == 'hey how are you' lol := 'lol lol lol' @@ -280,35 +290,43 @@ fn test_replace() { assert b.replace('B', '') == 'onetwothree' b = '*charptr' assert b.replace('charptr', 'byteptr') == '*byteptr' - c :='abc' - assert c.replace('','-') == c - v :='a b c d' - assert v.replace(' ',' ') == 'a b c d' - + c := 'abc' + assert c.replace('', '-') == c + v := 'a b c d' + assert v.replace(' ', ' ') == 'a b c d' } fn test_replace_each() { s := 'hello man man :)' q := s.replace_each([ - 'man', 'dude', - 'hello', 'hey' + 'man', + 'dude', + 'hello', + 'hey', ]) assert q == 'hey dude dude :)' bb := '[b]bold[/b] [code]code[/code]' assert bb.replace_each([ - '[b]', '', - '[/b]', '', - '[code]', '', - '[/code]', '' + '[b]', + '', + '[/b]', + '', + '[code]', + '', + '[/code]', + '', ]) == 'bold code' bb2 := '[b]cool[/b]' assert bb2.replace_each([ - '[b]', '', - '[/b]', '', + '[b]', + '', + '[/b]', + '', ]) == 'cool' t := 'aaaaaaaa' y := t.replace_each([ - 'aa', 'b' + 'aa', + 'b', ]) assert y == 'bbbb' } @@ -369,7 +387,7 @@ fn test_left_right() { assert s[..0] == '' assert s[..5] == s assert s[3..] == 'HA' - //assert s.right(6) == '' + // assert s.right(6) == '' u := s.ustring() assert u.left(3) == 'ALO' assert u.left(0) == '' @@ -425,7 +443,7 @@ fn test_to_num() { fn test_inter_format_string() { float_num := 1.52345 - float_num_string := '-${float_num:.03f}-' + float_num_string := '-${float_num:.3f}-' assert float_num_string == '-1.523-' int_num := 7 int_num_string := '-${int_num:03d}-' @@ -455,8 +473,8 @@ fn test_hash() { assert s4.hash() == -346636507 s5 := '24640' // From a map collision test - assert s5.hash() % ((1 << 20) -1) == s.hash() % ((1 << 20) -1) - assert s5.hash() % ((1 << 20) -1) == 592861 + assert s5.hash() % ((1 << 20) - 1) == s.hash() % ((1 << 20) - 1) + assert s5.hash() % ((1 << 20) - 1) == 592861 } fn test_trim() { @@ -599,7 +617,7 @@ fn test_capitalize() { s = 'test' assert !s.is_capital() assert s.capitalize() == 'Test' - s = 'i am ray' + s = 'i am ray' assert !s.is_capital() assert s.capitalize() == 'I am ray' s = '' @@ -645,14 +663,13 @@ fn test_for_loop_two() { } fn test_quote() { - a := `'` - println("testing double quotes") - b := "hi" + a := `\'` + println('testing double quotes') + b := 'hi' assert b == 'hi' - assert a.str() == '\'' + assert a.str() == "'" } - fn test_ustring_comparisons() { /* QTODO @@ -773,8 +790,8 @@ fn test_raw_with_quotes() { fn test_escape() { a := 10 - println("\"$a") - assert "\"$a" == "\"10" + println('\"$a') + assert '\"$a' == '"10' } fn test_atoi() { @@ -815,9 +832,9 @@ fn test_inter_before_comp_if() { fn test_double_quote_inter() { a := 1 b := 2 - println("${a} ${b}") - assert "${a} ${b}" == "1 2" - assert '${a} ${b}' == "1 2" + println('$a $b') + assert '$a $b' == '1 2' + assert '$a $b' == '1 2' } fn foo(b byte) byte { @@ -830,7 +847,7 @@ fn filter(b byte) bool { fn test_split_into_lines() { line_content := 'Line' - text_crlf := '${line_content}\r\n${line_content}\r\n${line_content}' + text_crlf := '$line_content\r\n$line_content\r\n$line_content' lines_crlf := text_crlf.split_into_lines() assert lines_crlf.len == 3 @@ -838,7 +855,7 @@ fn test_split_into_lines() { assert line == line_content } - text_lf := '${line_content}\n${line_content}\n${line_content}' + text_lf := '$line_content\n$line_content\n$line_content' lines_lf := text_lf.split_into_lines() assert lines_lf.len == 3 @@ -847,14 +864,11 @@ fn test_split_into_lines() { } } -fn test_string_literal_with_backslash(){ - a := 'Hello\ - World' - assert a == 'HelloWorld' +fn test_string_literal_with_backslash() { + a := 'HelloWorld' + assert a == 'HelloWorld' - b := 'One\ - Two\ - Three' + b := 'OneTwoThree' assert b == 'OneTwoThree' } @@ -887,7 +901,7 @@ fn test_sorter() { Ka{ s: 'ccc' i: 102 - } + }, ] cmp := fn (a &Ka, b &Ka) int { return compare_strings(a.s, b.s) @@ -902,10 +916,10 @@ fn test_sorter() { } fn test_split_by_whitespace() { - assert 'a bcde'.split_by_whitespace() == ['a', 'bcde'] - assert ' sss \t ssss '.split_by_whitespace() == ['sss', 'ssss'] - assert '\n xyz \t abc def'.split_by_whitespace() == ['xyz', 'abc', 'def'] - assert ''.split_by_whitespace() == [] + assert 'a bcde'.fields() == ['a', 'bcde'] + assert ' sss \t ssss '.fields() == ['sss', 'ssss'] + assert '\n xyz \t abc def'.fields() == ['xyz', 'abc', 'def'] + assert ''.fields() == [] } fn test_interpolation_after_quoted_variable_still_works() {