0

I am trying to remove leading and trailing spaces in a function but it does not work:

function Trim(s)
    echo ">>>".a:s."<<<"
    let ss = substitute(a:s, '\v^\s*([^\s]+)\s*$', '\1', '') 
    echo ">>>".ss."<<<"
endfunction

The regex \s*([^\s]+)\s* works ok on https://regex101.com/

Replacing * with + does not make any difference.

Testing:

: call Trim("   testing    ")

Output:

>>>   testing    <<<
>>>   testing    <<<

Also it seems to matter if I use double quotes versus single quotes in substitute function.

Where are the problems and how can they be solved? Thanks.

rnso
  • 23,686
  • 25
  • 112
  • 234

3 Answers3

3

Your issue is caused by your collection.

You should use [^ ] instead of [^\s]:

function! Trim(s)
    echo ">>>".a:s."<<<"
    let ss = substitute(a:s, '\v^\s*([^ ]+)\s*$', '\1', '') 
    echo ">>>".ss."<<<"
endfunction

This is because collections work on individual characters and \s is not an individual character; it's seen as \ followed by s, which doesn't resolve to anything because s is not a special character that needs escaping.

If you want your collection to include both spaces and tabs, use this:

[^ \t]
[ \t]

where \t represents a tab.

romainl
  • 186,200
  • 21
  • 280
  • 313
  • So far for my *buggy* comment on `\s`, tx Romain. Note that this interpretation of a collection seems to be vim specific?! The only regex flavor I find using the same interpretation is POSIX. – Lieven Keersmaekers May 31 '17 at 05:51
  • That explains the problem very well. I also see that the solution does not work if enclosed in double quotes rather than single quotes. What's the reason? (According to answer here https://stackoverflow.com/questions/13435586/should-i-use-single-or-double-quotes-in-my-vimrc-file , I expected double quotes to be required here). – rnso May 31 '17 at 05:59
  • Actually, in docs http://vimdoc.sourceforge.net/htmldoc/eval.html#substitute%28%29 , double quotes are being used. – rnso May 31 '17 at 06:13
  • @mso - I was going to make a case about performance but testing both solutions, it seems that any performance differences are negligable. – Lieven Keersmaekers May 31 '17 at 07:38
  • 1
    Escaping is done differently when you use double quotes or single quotes. With double quotes, `\s` is a literal ``\`` followed by a literal `s` and you would need to add another ``\`` to force Vim to treat `\s` as a character class. This would make your pattern look like this: `"\\v^\\s*([^ ]+)\\s*$"`. – romainl May 31 '17 at 07:38
2

As romainl explained, [^\s] means neither \ nor s. The contrary of \s (i.e. anything but a space or a tab) would be \S.

Otherwise, here is another solution: in lh-vim-lib I've defined the following

function! lh#string#trim(string) abort
  return matchstr(a:string, '^\v\_s*\zs.{-}\ze\_s*$')
endfunction

Regarding the difference(s) between the various kinds of quote characters, see this Q/A on vi.SE: https://vi.stackexchange.com/questions/9706/what-is-the-difference-between-single-and-double-quoted-strings

Luc Hermitte
  • 31,979
  • 7
  • 69
  • 83
1

You are including what needs to be retained in your search/replace. Much easier is to just look for what needs te be removed and substitute that

:%s/\v(^\s+|\s+$)//g

Breakdown

%s             Start a global search/replace
\v             Use Very Magic 
(^\s+          search for leading spaces
|              or
\s+$)          search for trailing spaces
//g            remove all search results from entire line
Lieven Keersmaekers
  • 57,207
  • 13
  • 112
  • 146