4

I'm trying to get into more advanced features of vimscript, so I'm trying to figure out how to use the map function, so I thought I'd write a function that returns every character with ASCII values between two numbers. For example,

CharRange(65, 90)

would give

ABCDEFGHIJKLMNOPQRSTUVWXYZ

So I tried this:

echo map(range(65, 90), function('nr2char'))

But I got some very strange results. Instead of giving ASCII 65-90, it gave ASCII 1-25.

^A ^B ^C ^D ^E ^F ^G ^H ^K ^L ^M ^N ^O ^P ^Q ^R ^S ^T ^U ^V ^W ^X ^Y

(of course it gave unprintables rather than the carets followed by letters)

After this didn't work, I tried some other ways, but none of them worked right. For example, a lambda:

echo join(map(range(50, 100), {arg1 -> nr2char(arg1)}))

This gives the exact same results. What am I doing wrong?

6

Looking at :h map:

map({expr1}, {expr2})                                   map()
                {expr1} must be a List or a Dictionary.
                Replace each item in {expr1} with the result of evaluating
                {expr2}.  {expr2} must be a string or Funcref.             
...
                If {expr2} is a Funcref it is called with two arguments:
                        1. The key or the index of the current item.
                        2. the value of the current item.

Therefore, what map does for 65 in this case actually call nr2char(0, 65), and for nr2char:

nr2char({expr}[, {utf8}])                               nr2char()
                Return a string with a single character, which has the number
                value {expr}.  ...
               When {utf8} is omitted or zero, the current 'encoding' is used.
                Example for "utf-8": 
                        nr2char(300)            returns I with bow character
               With {utf8} set to 1, always return utf-8 characters.

So, the 65 is pretty much ignored, and you get the U+0 character:

['', '^A', '^B', '^C', '^D', '^E', '^F', '^G', '^H', '  ', '
', '^N', '^O', '^P', '^Q', '^R', '^S', '^T', '^U', '^V', '^W', '^X', '^Y']

See man 7 ascii.

The help does have an example of this problem, but it's in :h lambda:

Examples for using a lambda expression with sort(), map() and filter(): 
    :echo map([1, 2, 3], {idx, val -> val + 1})
   [2, 3, 4] 
    :echo sort([3,7,2,1,4], {a, b -> a - b})
   [1, 2, 3, 4, 7]

The first example shows that map passes two arguments, and the second is the actual value.

  • I get what the problem is but I can't figure how to solve it? – statox Nov 8 '16 at 10:29
  • 3
    @statox OP knows how to use lambdas, so I figured it'd be a quick step from this to one solution: map(range(65, 90), {k, v -> nr2char(v)}). Or, using the String version of map: map(range(65, 90), 'nr2char(v:val)'). – muru Nov 8 '16 at 10:40
  • I was trying to use v:val with no success. Thanks for your answer! – statox Nov 8 '16 at 10:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.