Loading ...
Sorry, an error occurred while loading the content.

Re: Calling a function from a :s command (weird results)

Expand Messages
  • Benji Fisher
    ... I think you are right. Let s try to make it as simple as possible: fun! Boring(str) return substitute(a:str, ^ , = , ) endfun ... foo ... inserts
    Message 1 of 11 , Dec 1, 2003
    • 0 Attachment
      On Mon, Dec 01, 2003 at 01:22:40AM -0500, John Aldridge wrote:
      > At 23:42 11-30-2003, Klaus Bosau wrote:
      >
      > I ran a couple of tests and the results are interesting.
      >
      > Could it be that submatching can't be nested?
      >
      >
      > function! TestSubSub(str)
      > if 1
      > return substitute(a:str, 'h\(i\)', '\=strlen(submatch(1))', 'g')
      > " Produces:
      > " T=strlen(submatch(1))s is some sample text.
      > else
      > return substitute(a:str, 'h\(i\)', strlen(submatch(1)), 'g')
      > " Produces:
      > " T2s is some sample text.
      > " Interesting:
      > " The 2 is the submatch strlen from outside this call!!!
      > endif
      > endfunction
      >
      > " This is some sample text.
      > " Try: %s/Th\(is\)/\=TestSubSub(submatch(0))/

      I think you are right. Let's try to make it as simple as possible:

      fun! Boring(str)
      return substitute(a:str, '^', '\=""', '')
      endfun

      This function returns its argument, as a little test shows:

      :echo Boring("foo")
      foo

      However, when I try to use it inside a \= expression, it does not work:

      :s/^/\=Boring("foo")

      inserts '=""foo' instead of just 'foo'.

      I think the problem is with nesting \= , whether or not you use
      submatches.

      I assume that this worked when the InvertString() function was
      first posted to the list, but broken by a later patch. The oldest
      version of vim that I have lying around is 6.1.400. Does anyone with an
      older version get different results?

      --Benji Fisher
    • Klaus Bosau
      ... (I recently upgraded to 6.2, so I can t answer your question.) Just for those who are interested.. Preben was indeed right, InvertString() turned out to be
      Message 2 of 11 , Dec 1, 2003
      • 0 Attachment
        On Mon, 1 Dec 2003, Benji Fisher wrote:

        > [...]
        >
        > I assume that this worked when the InvertString() function was
        > first posted to the list, but broken by a later patch. The oldest
        > version of vim that I have lying around is 6.1.400. Does anyone with
        > an older version get different results?

        (I recently upgraded to 6.2, so I can't answer your question.) Just for
        those who are interested.. Preben was indeed right, InvertString()
        turned out to be about twice as fast as a comparable solution based on a
        :while loop.

        For

        function! InvertString(str)
        let inverted = ''
        let n = strlen(a:str) - 1
        while n >= 0
        let inverted = inverted . a:str[n]
        let n = n - 1
        endwhile
        return inverted
        endfunction

        and

        let n = 3000
        while n > 0
        let x = InvertString('abcdefghijklmnopqrstuvwxyz')
        let n = n - 1
        endwhile

        I got 10 and 5 seconds..

        Klaus
      • Benji Fisher
        ... I get similar results: 5 seconds for the original version, 9 seconds for yours. This version takes 6 seconds: function! IS2(str) let n = strlen(a:str)
        Message 3 of 11 , Dec 1, 2003
        • 0 Attachment
          On Mon, Dec 01, 2003 at 04:41:30PM +0100, Klaus Bosau wrote:
          > On Mon, 1 Dec 2003, Benji Fisher wrote:
          >
          > > [...]
          > >
          > > I assume that this worked when the InvertString() function was
          > > first posted to the list, but broken by a later patch. The oldest
          > > version of vim that I have lying around is 6.1.400. Does anyone with
          > > an older version get different results?
          >
          > (I recently upgraded to 6.2, so I can't answer your question.) Just for
          > those who are interested.. Preben was indeed right, InvertString()
          > turned out to be about twice as fast as a comparable solution based on a
          > :while loop.
          >
          > For
          >
          > function! InvertString(str)
          > let inverted = ''
          > let n = strlen(a:str) - 1
          > while n >= 0
          > let inverted = inverted . a:str[n]
          > let n = n - 1
          > endwhile
          > return inverted
          > endfunction
          >
          > and
          >
          > let n = 3000
          > while n > 0
          > let x = InvertString('abcdefghijklmnopqrstuvwxyz')
          > let n = n - 1
          > endwhile
          >
          > I got 10 and 5 seconds..
          >
          > Klaus

          I get similar results: 5 seconds for the original version, 9
          seconds for yours. This version takes 6 seconds:

          function! IS2(str)
          let n = strlen(a:str)
          let m = n/2
          let inverted = (n%2 ? a:str[m] : '')
          while m
          let inverted = a:str[n-m] . inverted . a:str[m-1]
          let m = m-1
          endwhile
          return inverted
          endfunction

          It would probably be faster if someone got to this item from todo.txt:

          8 Add ":let var[{expr}] = {expr}". When past the end of "var" just ignore.

          The recursive version takes 14 seconds.

          --Benji Fisher
        • Charles E. Campbell, Jr.
          ... Since = doesn t nest, I thought I d donate a couple of maps. They don t work with = in a substitute, but they will mirror-reverse the order of characters
          Message 4 of 11 , Dec 1, 2003
          • 0 Attachment
            David Fishburn wrote:

            >I have this function (from a previous posting):
            >
            >
            >
            Since \= doesn't nest, I thought I'd donate a couple of maps.

            They don't work with \= in a substitute, but they will mirror-reverse
            the order of characters on the current line:

            nmap <Leader>fR :set
            lz<CR>o<Esc>mqkO<Esc>mpj:s/./&\r/ge<CR>:'p+1,'q-1g/^/m
            'p<CR>:'p+1,'q-1j!<CR>'pdd'qddk:set nolz<CR>

            vmap <Leader>fR :<C-U>set lz<CR>:let ai=&ai<CR>:set
            noai<CR>`>maa<CR><Esc>`<i<CR><Esc>jmz:'a+1,'z-1s/./&\r/g<CR>:'a+1,'z-1g/^/m
            'a<CR>:'a,'zj!<CR>:let &ai=ai<CR>:set nolz<CR>

            The two maps should be on one line, of course.

            To use \fR on a range of lines:

            :[range]norm \fR

            will do the trick.

            Regards,
            Chip Campbell
          Your message has been successfully submitted and would be delivered to recipients shortly.