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

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

Expand Messages
  • David Fishburn
    Vim 6.2.154 WinXP I have this function (from a previous posting): function! InvertString(str) Courtesy of Antony Scriven This will invert/reverse a string
    Message 1 of 11 , Nov 30, 2003
    • 0 Attachment
      Vim 6.2.154 WinXP

      I have this function (from a previous posting):

      function! InvertString(str)
      " Courtesy of Antony Scriven
      " This will invert/reverse a string
      " This will work on arbitrary length strings, too. The /.*/ should
      be
      " quick, which might make it up for using a regex rather than using
      " numerous commands in a :while loop.
      "
      " This can be used in a substitute command as follows:
      " :%s/AUTHORIZATION/\=InvertString(submatch(0))
      let inverted = substitute(a:str, '.\(.*\)\@=',
      \ '\=a:str[strlen(submatch(1))]', 'g')

      return inverted
      endfunction


      I have this file:
      CREATE SERVICE "scores" TYPE 'RAW'
      OFF USER DBA
      URL ON
      AS CALL sp_http_scores();

      CREATE SERVICE "scores" TYPE 'RAW'
      AUTHORIZATION OFF USER DBA
      URL ON
      AS CALL sp_http_scores();

      I issue this command:
      :%s/AUTHORIZATION/\=InvertString(submatch(0))

      I get this result, and I don't understand why:
      CREATE SERVICE "scores" TYPE 'RAW'

      =a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(subm
      atch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[st
      rlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]
      =a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(subm
      atch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))] OFF USER
      DBA
      URL ON
      AS CALL sp_http_scores();

      CREATE SERVICE "scores" TYPE 'RAW'

      =a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(subm
      atch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[st
      rlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]
      =a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(subm
      atch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))] OFF USER
      DBA
      URL ON
      AS CALL sp_http_scores();

      This works fine:
      :echo InvertString('1234567890')
      0987654321 is displayed.

      Any ideas?

      Thanks,
      Dave
    • John Aldridge
      ... I get this kind of thing once in a while; and if I remember correctly, it s a quoting issue. From your results, it looks as if the = isn t being taken
      Message 2 of 11 , Nov 30, 2003
      • 0 Attachment
        At 19:24 11-30-2003, David Fishburn wrote:


        >Vim 6.2.154 WinXP
        >
        >I have this function (from a previous posting):
        >
        >function! InvertString(str)
        > " Courtesy of Antony Scriven
        > " This will invert/reverse a string
        > " This will work on arbitrary length strings, too. The /.*/ should
        >be
        > " quick, which might make it up for using a regex rather than using
        > " numerous commands in a :while loop.
        > "
        > " This can be used in a substitute command as follows:
        > " :%s/AUTHORIZATION/\=InvertString(submatch(0))
        > let inverted = substitute(a:str, '.\(.*\)\@=',
        > \ '\=a:str[strlen(submatch(1))]', 'g')
        >
        > return inverted
        >endfunction
        >
        >
        >I have this file:
        >CREATE SERVICE "scores" TYPE 'RAW'
        > OFF USER DBA
        > URL ON
        > AS CALL sp_http_scores();
        >
        >CREATE SERVICE "scores" TYPE 'RAW'
        > AUTHORIZATION OFF USER DBA
        > URL ON
        > AS CALL sp_http_scores();
        >
        >I issue this command:
        >:%s/AUTHORIZATION/\=InvertString(submatch(0))
        >
        >I get this result, and I don't understand why:
        >CREATE SERVICE "scores" TYPE 'RAW'
        >
        >=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(subm
        >atch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[st
        >rlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]
        >=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(subm
        >atch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))] OFF USER
        >DBA
        > URL ON
        > AS CALL sp_http_scores();
        >
        >CREATE SERVICE "scores" TYPE 'RAW'
        >
        >=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(subm
        >atch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[st
        >rlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]
        >=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(subm
        >atch(1))]=a:str[strlen(submatch(1))]=a:str[strlen(submatch(1))] OFF USER
        >DBA
        > URL ON
        > AS CALL sp_http_scores();
        >
        >This works fine:
        >:echo InvertString('1234567890')
        >0987654321 is displayed.
        >
        >Any ideas?
        >
        >Thanks,
        >Dave

        I get this kind of thing once in a while; and if I remember correctly,
        it's a quoting issue. From your results, it looks as if the \= isn't
        being taken for its intended meaning. Without remembering what really
        fixes this, I'd say go ahead and throw an extra backslash in there.
      • Antony Scriven
        ... Actually Preben Guldberg wrote this function. Antony
        Message 3 of 11 , Nov 30, 2003
        • 0 Attachment
          On Nov 30, David Fishburn wrote:

          > I have this function (from a previous posting):
          >
          > function! InvertString(str)
          > " Courtesy of Antony Scriven
          > " This will invert/reverse a string
          > " This will work on arbitrary length strings, too. The /.*/ should be
          > " quick, which might make it up for using a regex rather than using
          > " numerous commands in a :while loop.
          > "
          > " This can be used in a substitute command as follows:
          > " :%s/AUTHORIZATION/\=InvertString(submatch(0))
          > let inverted = substitute(a:str, '.\(.*\)\@=',
          > \ '\=a:str[strlen(submatch(1))]', 'g')
          >
          > return inverted
          > endfunction

          Actually Preben Guldberg wrote this function.

          Antony
        • Klaus Bosau
          ... Just a guess.. Flag C in cpo ? Klaus
          Message 4 of 11 , Nov 30, 2003
          • 0 Attachment
            On Sun, 30 Nov 2003, John Aldridge wrote:

            > I get this kind of thing once in a while; and if I remember correctly,
            > it's a quoting issue. From your results, it looks as if the \= isn't
            > being taken for its intended meaning. Without remembering what really
            > fixes this, I'd say go ahead and throw an extra backslash in there.

            Just a guess.. Flag 'C' in 'cpo'?

            Klaus
          • David Fishburn
            ... Nope. cpoptions=aABceFs Dave
            Message 5 of 11 , Nov 30, 2003
            • 0 Attachment
              > > I get this kind of thing once in a while; and if I remember
              > correctly,
              > > it's a quoting issue. From your results, it looks as if
              > the \= isn't
              > > being taken for its intended meaning. Without remembering
              > what really
              > > fixes this, I'd say go ahead and throw an extra backslash in there.
              >
              > Just a guess.. Flag 'C' in 'cpo'?

              Nope.
              cpoptions=aABceFs

              Dave
            • Klaus Bosau
              ... Second try.. function! InvertString(str) Courtesy of Antony Scriven This will invert/reverse a string This will work on arbitrary length strings,
              Message 6 of 11 , Nov 30, 2003
              • 0 Attachment
                On Sun, 30 Nov 2003, David Fishburn wrote:

                >>> I get this kind of thing once in a while; and if I remember correctly,
                >>> it's a quoting issue. From your results, it looks as if the \= isn't
                >>> being taken for its intended meaning. Without remembering what really
                >>> fixes this, I'd say go ahead and throw an extra backslash in there.
                >>
                >> Just a guess.. Flag 'C' in 'cpo'?
                >
                > Nope.
                > cpoptions=aABceFs

                Second try..

                function! InvertString(str)
                " Courtesy of Antony Scriven
                " This will invert/reverse a string
                " This will work on arbitrary length strings, too. The /.*/ should
                be
                ^
                " quick, which might make it up for using a regex rather than using
                " numerous commands in a :while loop.
                "
                " This can be used in a substitute command as follows:
                " :%s/AUTHORIZATION/\=InvertString(submatch(0))
                let inverted = substitute(a:str, '.\(.*\)\@=',
                \ '\=a:str[strlen(submatch(1))]', 'g')

                return inverted
                endfunction

                Klaus
              • John Aldridge
                ... 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
                Message 7 of 11 , Nov 30, 2003
                • 0 Attachment
                  At 23:42 11-30-2003, Klaus Bosau wrote:

                  >On Sun, 30 Nov 2003, David Fishburn wrote:
                  >
                  > >>> I get this kind of thing once in a while; and if I remember correctly,
                  > >>> it's a quoting issue. From your results, it looks as if the \= isn't
                  > >>> being taken for its intended meaning. Without remembering what really
                  > >>> fixes this, I'd say go ahead and throw an extra backslash in there.
                  > >>
                  > >> Just a guess.. Flag 'C' in 'cpo'?
                  > >
                  > > Nope.
                  > > cpoptions=aABceFs
                  >
                  >Second try..
                  >
                  > function! InvertString(str)
                  > " Courtesy of Antony Scriven
                  > " This will invert/reverse a string
                  > " This will work on arbitrary length strings, too. The /.*/ should
                  > be
                  > ^
                  > " quick, which might make it up for using a regex rather than using
                  > " numerous commands in a :while loop.
                  > "
                  > " This can be used in a substitute command as follows:
                  > " :%s/AUTHORIZATION/\=InvertString(submatch(0))
                  > let inverted = substitute(a:str, '.\(.*\)\@=',
                  > \ '\=a:str[strlen(submatch(1))]', 'g')
                  >
                  > return inverted
                  > endfunction
                  >
                  >Klaus


                  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))/


                  ~
                  ~
                  ~
                  "John R. Aldridge, Jr."
                • 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 8 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 9 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 10 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 11 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.