From 2d5c7c8e93d0da4da7467eb3c077df951d55b9b4 Mon Sep 17 00:00:00 2001 From: Major Taylor Date: Sun, 15 Mar 2020 00:46:12 -0400 Subject: [PATCH] string: add `strip_margin` --- vlib/builtin/string.v | 61 ++++++++++++++++++++++++++++++ vlib/builtin/string_test.v | 76 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 0b86f97083..6296ea3531 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -1267,3 +1267,64 @@ pub fn (s string) repeat(count int) string { ret[s.len * count] = 0 return string(ret) } + +// Allows multi-line strings to be formatted in a way that removes white-space +// before a delimeter. by default `|` is used. +// Note: the delimiter has to be a byte at this time. That means surrounding +// the value in ``. +// +// Example: +// st := 'Hello there, +// |this is a string, +// | Everything before the first | is removed'.strip_margin() +// Returns: +// Hello there, +// this is a string, +// Everything before the first | is removed +pub fn (s string) strip_margin(del ...byte) string { + mut sep := `|` + if del.len >= 1 { + // This is a workaround. We can't directly index a var_args array. + // Only care about the first one, ignore the rest if more + for d in del { + // The delimiter is not allowed to be white-space. Will use default + if !d.is_space() { + sep = d + } else { + eprintln("Warning: `strip_margin` cannot use white-space as a delimiter") + eprintln(" Defaulting to `|`") + } + break + } + if del.len == 1 { + eprintln("Warning: `strip_margin` only uses the first argument given") + } + } + // don't know how much space the resulting string will be, but the max it + // can be is this big + mut ret := malloc(s.len + 1) + mut count := 0 + for i := 0; i < s.len; i++ { + if (s[i] in [`\n`, `\r`]) { + $if windows { + ret[count] = `\r` + ret[count+1] = `\n` + count += 2 + } $else { + ret[count] = s[i] + count++ + } + for s[i] != sep { + i++ + if i >= s.len { + break + } + } + } else { + ret[count] = s[i] + count++ + } + } + ret[count] = 0 + return string(ret) +} diff --git a/vlib/builtin/string_test.v b/vlib/builtin/string_test.v index 3c6675d422..15211eba13 100644 --- a/vlib/builtin/string_test.v +++ b/vlib/builtin/string_test.v @@ -695,3 +695,79 @@ fn test_split_into_lines() { assert line == line_content } } + +fn test_strip_margins() { + no_tabs := 'Hello there +This is a string +With multiple lines' + no_tabs_stripped := 'Hello there + |This is a string + |With multiple lines'.strip_margin() + assert no_tabs == no_tabs_stripped + + text_before := 'There is text +before the delimiter +that should be removed as well' + text_before_stripped := 'There is text + f lasj asldfj j lksjdf |before the delimiter + Which is removed hello |that should be removed as well'.strip_margin() + assert text_before_stripped == text_before + + tabs := ' Tab + spaces + another tab' + tabs_stripped := ' Tab + | spaces + | another tab'.strip_margin() + assert tabs == tabs_stripped + + alternate_delimiter := 'This has a different delim, +but that is ok + because everything works' + alternate_delimiter_stripped := 'This has a different delim, + #but that is ok + # because everything works'.strip_margin(`#`) + assert alternate_delimiter_stripped == alternate_delimiter + + delim_after_first_instance := 'The delimiter used +only matters the |||| First time it is seen +not any | other | times' + delim_after_first_instance_stripped := 'The delimiter used + |only matters the |||| First time it is seen + |not any | other | times'.strip_margin() + assert delim_after_first_instance_stripped == delim_after_first_instance + + uneven_delims := 'It doesn\'t matter if the delims are uneven, +The text will still be delimited correctly. +Maybe not everything needs 3 lines? +Let us go for 4 then' + uneven_delims_stripped := 'It doesn\'t matter if the delims are uneven, + |The text will still be delimited correctly. + |Maybe not everything needs 3 lines? + |Let us go for 4 then'.strip_margin() + assert uneven_delims_stripped == uneven_delims + + multi_blank_lines := 'Multiple blank lines will be removed. + I actually consider this a feature.' + multi_blank_lines_stripped := 'Multiple blank lines will be removed. + + + + | I actually consider this a feature.'.strip_margin() + assert multi_blank_lines == multi_blank_lines_stripped + + end_with_newline := 'This line will end with a newline +Something cool or something. +' + end_with_newline_stripped := 'This line will end with a newline + |Something cool or something. + + '.strip_margin() + assert end_with_newline_stripped == end_with_newline + + space_delimiter := 'Using a white-space char will +revert back to default behavior.' + space_delimiter_stripped := 'Using a white-space char will + |revert back to default behavior.'.strip_margin(`\n`) + assert space_delimiter == space_delimiter_stripped +}