1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

builtin: add rsplit functions (#17577)

This commit is contained in:
ChAoS_UnItY 2023-03-11 07:07:02 +08:00 committed by GitHub
parent ee4150f213
commit 9fa49da9d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 287 additions and 0 deletions

View File

@ -757,6 +757,36 @@ pub fn (s string) split_any(delim string) []string {
return res
}
// rsplit_any splits the string to an array by any of the `delim` chars in reverse order.
// Example: "first row\nsecond row".rsplit_any(" \n") == ['row', 'second', 'row', 'first']
// Split a string using the chars in the delimiter string as delimiters chars.
// If the delimiter string is empty then `.rsplit()` is used.
[direct_array_access]
pub fn (s string) rsplit_any(delim string) []string {
mut res := []string{}
mut i := s.len - 1
if s.len > 0 {
if delim.len <= 0 {
return s.rsplit('')
}
mut rbound := s.len
for i >= 0 {
for delim_ch in delim {
if s[i] == delim_ch {
res << s[i + 1..rbound]
rbound = i
break
}
}
i--
}
if rbound > 0 {
res << s[..rbound]
}
}
return res
}
// split splits the string to an array by `delim`.
// Example: assert 'A B C'.split(' ') == ['A','B','C']
// If `delim` is empty the string is split by it's characters.
@ -765,6 +795,52 @@ pub fn (s string) split(delim string) []string {
return s.split_nth(delim, 0)
}
// rsplit splits the string to an array by `delim` in reverse order.
// Example: assert 'A B C'.rsplit(' ') == ['C','B','A']
// If `delim` is empty the string is split by it's characters.
// Example: assert 'DEF'.rsplit('') == ['F','E','D']
pub fn (s string) rsplit(delim string) []string {
return s.rsplit_nth(delim, 0)
}
// split_once devides string into pair of string by `delim`.
// Example:
// ```v
// path, ext := 'file.ts.dts'.splice_once('.')?
// assert path == 'file'
// assert ext == 'ts.dts'
// ```
// Note that rsplit_once returns splitted string string as first part of pair,
// and returns remaining as second part of pair.
pub fn (s string) split_once(delim string) ?(string, string) {
result := s.split_nth(delim, 2)
if result.len != 2 {
return none
}
return result[0], result[1]
}
// rsplit_once devides string into pair of string by `delim`.
// Example:
// ```v
// path, ext := 'file.ts.dts'.splice_once('.')?
// assert path == 'file.ts'
// assert ext == 'dts'
// ```
// Note that rsplit_once returns remaining string as first part of pair,
// and returns splitted string as second part of pair.
pub fn (s string) rsplit_once(delim string) ?(string, string) {
result := s.rsplit_nth(delim, 2)
if result.len != 2 {
return none
}
return result[1], result[0]
}
// split_nth splits the string based on the passed `delim` substring.
// It returns the first Nth parts. When N=0, return all the splits.
// The last returned element has the remainder of the string, even if
@ -839,6 +915,74 @@ pub fn (s string) split_nth(delim string, nth int) []string {
}
}
// rsplit_nth splits the string based on the passed `delim` substring in revese order.
// It returns the first Nth parts. When N=0, return all the splits.
// The last returned element has the remainder of the string, even if
// the remainder contains more `delim` substrings.
[direct_array_access]
pub fn (s string) rsplit_nth(delim string, nth int) []string {
mut res := []string{}
mut i := s.len - 1
match delim.len {
0 {
for i >= 0 {
if nth > 0 && res.len == nth - 1 {
res << s[..i]
break
}
res << s[i].ascii_str()
i--
}
return res
}
1 {
mut rbound := s.len
delim_byte := delim[0]
for i >= 0 {
if s[i] == delim_byte {
if nth > 0 && res.len == nth - 1 {
break
}
res << s[i + 1..rbound]
rbound = i
i--
} else {
i--
}
}
if nth < 1 || res.len < nth {
res << s[..rbound]
}
return res
}
else {
mut rbound := s.len
for i >= 0 {
is_delim := i - delim.len >= 0 && s[i - delim.len..i] == delim
if is_delim {
if nth > 0 && res.len == nth - 1 {
break
}
res << s[i..rbound]
rbound = i - delim.len
i -= delim.len
} else {
i--
}
}
if nth < 1 || res.len < nth {
res << s[..rbound]
}
return res
}
}
}
// split_into_lines splits the string by newline characters.
// newlines are stripped.
// `\r` (MacOS), `\n` (POSIX), and `\r\n` (WinOS) line endings are all supported (including mixed line endings).

View File

@ -188,6 +188,37 @@ fn test_split_nth() {
assert e.split_nth(',', 3).len == 3
}
fn test_rsplit_nth() {
a := '1,2,3'
assert a.rsplit(',').len == 3
assert a.rsplit_nth(',', -1).len == 3
assert a.rsplit_nth(',', 0).len == 3
assert a.rsplit_nth(',', 1).len == 1
assert a.rsplit_nth(',', 2).len == 2
assert a.rsplit_nth(',', 10).len == 3
b := '1::2::3'
assert b.rsplit('::').len == 3
assert b.rsplit_nth('::', -1).len == 3
assert b.rsplit_nth('::', 0).len == 3
assert b.rsplit_nth('::', 1).len == 1
assert b.rsplit_nth('::', 2).len == 2
assert b.rsplit_nth('::', 10).len == 3
c := 'ABCDEF'
assert c.rsplit('').len == 6
assert c.rsplit_nth('', 3).len == 3
assert c.rsplit_nth('BC', -1).len == 2
d := ','
assert d.rsplit(',').len == 2
assert d.rsplit_nth('', 3).len == 1
assert d.rsplit_nth(',', -1).len == 2
assert d.rsplit_nth(',', 3).len == 2
e := ',,,0,,,,,a,,b,'
assert e.rsplit(',,').len == 5
assert e.rsplit_nth(',,', 3).len == 3
assert e.rsplit_nth(',', -1).len == 12
assert e.rsplit_nth(',', 3).len == 3
}
fn test_split_nth_values() {
line := 'CMD=eprintln(phase=1)'
@ -219,6 +250,37 @@ fn test_split_nth_values() {
assert a4[2] == '1)'
}
fn test_rsplit_nth_values() {
line := 'CMD=eprintln(phase=1)'
a0 := line.rsplit_nth('=', 0)
assert a0.len == 3
assert a0[0] == '1)'
assert a0[1] == 'eprintln(phase'
assert a0[2] == 'CMD'
a1 := line.rsplit_nth('=', 1)
assert a1.len == 1
assert a1[0] == 'CMD=eprintln(phase=1)'
a2 := line.rsplit_nth('=', 2)
assert a2.len == 2
assert a2[0] == '1)'
assert a2[1] == 'CMD=eprintln(phase'
a3 := line.rsplit_nth('=', 3)
assert a3.len == 3
assert a0[0] == '1)'
assert a0[1] == 'eprintln(phase'
assert a0[2] == 'CMD'
a4 := line.rsplit_nth('=', 4)
assert a4.len == 3
assert a0[0] == '1)'
assert a0[1] == 'eprintln(phase'
assert a0[2] == 'CMD'
}
fn test_split() {
mut s := 'volt/twitch.v:34'
mut vals := s.split(':')
@ -265,6 +327,52 @@ fn test_split() {
assert vals[1] == ''
}
fn test_rsplit() {
mut s := 'volt/twitch.v:34'
mut vals := s.rsplit(':')
assert vals.len == 2
assert vals[0] == '34'
assert vals[1] == 'volt/twitch.v'
// /////////
s = '2018-01-01z13:01:02'
vals = s.rsplit('z')
assert vals.len == 2
assert vals[0] == '13:01:02'
assert vals[1] == '2018-01-01'
// //////////
s = '4627a862c3dec29fb3182a06b8965e0025759e18___1530207969___blue'
vals = s.rsplit('___')
assert vals.len == 3
assert vals[0] == 'blue'
assert vals[1] == '1530207969'
assert vals[2] == '4627a862c3dec29fb3182a06b8965e0025759e18'
// /////////
s = 'lalala'
vals = s.rsplit('a')
assert vals.len == 4
assert vals[0] == ''
assert vals[1] == 'l'
assert vals[2] == 'l'
assert vals[3] == 'l'
// /////////
s = 'awesome'
a := s.rsplit('')
assert a.len == 7
assert a[0] == 'e'
assert a[1] == 'm'
assert a[2] == 'o'
assert a[3] == 's'
assert a[4] == 'e'
assert a[5] == 'w'
assert a[6] == 'a'
// /////////
s = 'wavy turquoise bags'
vals = s.rsplit('wavy ')
assert vals.len == 2
assert vals[0] == 'turquoise bags'
assert vals[1] == ''
}
fn test_split_any() {
assert 'ABC'.split_any('') == ['A', 'B', 'C']
assert ''.split_any(' ') == []
@ -276,6 +384,41 @@ fn test_split_any() {
assert 'first row\nsecond row'.split_any(' \n') == ['first', 'row', 'second', 'row']
}
fn test_rsplit_any() {
assert 'ABC'.rsplit_any('') == ['C', 'B', 'A']
assert ''.rsplit_any(' ') == []
assert ' '.rsplit_any(' ') == ['']
assert ' '.rsplit_any(' ') == ['', '']
assert ' Ciao come stai?'.rsplit_any(' ') == ['stai?', 'come', 'Ciao']
assert ' Ciao+come*stai?'.rsplit_any('+*') == ['stai?', 'come', ' Ciao']
assert ' Ciao+come*stai?'.rsplit_any('+* ') == ['stai?', 'come', 'Ciao']
assert 'first row\nsecond row'.rsplit_any(' \n') == ['row', 'second', 'row', 'first']
}
fn test_split_once() ? {
path1, ext1 := 'home/dir/lang.zip'.split_once('.')?
assert path1 == 'home/dir/lang'
assert ext1 == 'zip'
path2, ext2 := 'home/dir/lang.ts.dts'.split_once('.')?
assert path2 == 'home/dir/lang'
assert ext2 == 'ts.dts'
path3, ext3 := 'home/dir'.split_once('.') or { '', '' }
assert path3 == ''
assert ext3 == ''
}
fn test_rsplit_once() ? {
path1, ext1 := 'home/dir/lang.zip'.rsplit_once('.')?
assert path1 == 'home/dir/lang'
assert ext1 == 'zip'
path2, ext2 := 'home/dir/lang.ts.dts'.rsplit_once('.')?
assert path2 == 'home/dir/lang.ts'
assert ext2 == 'dts'
path3, ext3 := 'home/dir'.rsplit_once('.') or { '', '' }
assert path3 == ''
assert ext3 == ''
}
fn test_trim_space() {
a := ' a '
assert a.trim_space() == 'a'