Vim Tips Wiki
Advertisement
Tip 27 Printable Monobook Previous Next

created 2001 · complexity basic · version 7.0


This tip shows how to convert numbers from hexadecimal to decimal and vice versa. A variety of methods are given, starting with some simple commands, and including scripts to easily replace hex with decimal numbers, or to replace decimal with hex. Handling percent-encoded text is also discussed.

Commands

Occasional conversions can be performed by entering commands. In Vim, put the cursor on 0x12345 and type :echo then Space Ctrl-R Ctrl-W Enter. That will execute :echo 0x12345 which displays 74565 (decimal equivalent of hex 12345).

An example of converting decimal to hex would be to enter :echo printf('%x',74565) which displays 12345 (hex equivalent of decimal 74565).

In normal mode, type ga to display the decimal and hex values for the character under the cursor, or type g8 to display the hex bytes for a UTF-8 character.

The following commands illustrate other simple techniques to convert strings to numbers which are displayed in decimal (the :echo is just for illustration; these techniques would be used in a script). The first shows that adding zero to a string converts the string to a number.

Command Output Description
:echo '0012' + 0 10 octal 12 due to leading zero
:echo str2nr('0012') 12 decimal 12 (leading zeros ignored)
:echo str2nr('0x0a2f', 16) 2607 hex a2f
:echo str2nr('0a2f', 16) 2607 same ('0x' not required with base 16)
:echo str2nr('^R^W', 16) (decimal) hex word under cursor (press Ctrl-R Ctrl-W)

The following convert decimal numbers to hex strings.

Command Output Description
:echo printf('%x', 1234) 4d2 decimal 1234 in hex
:echo printf('%04x', 1234) 04d2 same, with leading zeros to four digits
:echo printf('%x', ^R^W) (hex) decimal word under cursor (press Ctrl-R Ctrl-W)

Copying a hex number as decimal

With the following mapping, you can put the cursor on a hex number and press \h (assuming the default backslash leader) to yank the value of the hex number (using :let means the equivalent decimal string is copied). You can then move the cursor elsewhere and press p to paste the decimal value.

nnoremap \h :let @@=<C-R><C-W><CR>

Alternatively, you can use a global variable to avoid using a register. With these mappings, \h will yank a hex value, and \p will paste the decimal string:

nnoremap \h :let Value=<C-R><C-W><CR>
nnoremap \p :if exists('Value')<Bar>normal i<C-R>=Value<CR><Esc><Bar>:endif<CR>

User commands

Put the following in your vimrc to define user commands to convert between hex and decimal. You can convert a number entered on the command line, or all numbers in selected text.

command! -nargs=? -range Dec2hex call s:Dec2hex(<line1>, <line2>, '<args>')
function! s:Dec2hex(line1, line2, arg) range
  if empty(a:arg)
    if histget(':', -1) =~# "^'<,'>" && visualmode() !=# 'V'
      let cmd = 's/\%V\<\d\+\>/\=printf("0x%x",submatch(0)+0)/g'
    else
      let cmd = 's/\<\d\+\>/\=printf("0x%x",submatch(0)+0)/g'
    endif
    try
      execute a:line1 . ',' . a:line2 . cmd
    catch
      echo 'Error: No decimal number found'
    endtry
  else
    echo printf('%x', a:arg + 0)
  endif
endfunction

command! -nargs=? -range Hex2dec call s:Hex2dec(<line1>, <line2>, '<args>')
function! s:Hex2dec(line1, line2, arg) range
  if empty(a:arg)
    if histget(':', -1) =~# "^'<,'>" && visualmode() !=# 'V'
      let cmd = 's/\%V0x\x\+/\=submatch(0)+0/g'
    else
      let cmd = 's/0x\x\+/\=submatch(0)+0/g'
    endif
    try
      execute a:line1 . ',' . a:line2 . cmd
    catch
      echo 'Error: No hex number starting "0x" found'
    endtry
  else
    echo (a:arg =~? '^0x') ? a:arg + 0 : ('0x'.a:arg) + 0
  endif
endfunction

The above defines user commands :Dec2hex and :Hex2dec that will either display the result of converting a number that you enter, or will convert all numbers in selected text. A decimal number is a word consisting only of decimal digits, while a hex number consists of "0x" followed by one or more hex digits.

If no argument is entered with these commands, a range may be specified. The default range is the current line. A visual selection (character, line, or block) can also specify a range. When using a visual block (selection starts with Ctrl-V, or Ctrl-Q if Ctrl-V is used for paste), only numbers inside the block are converted. Example commands:

Command Description
:Dec2hex 496 Displays 1f0 (hex equivalent of decimal 496).
:Dec2hex Converts all decimal numbers to hex in current line.
:'<,>'Dec2hex Same, for all visually selected text (v, V, or ^V).
:%Dec2hex Same, for all lines in buffer.
:Hex2dec 0x1f0 Displays 496 (decimal equivalent of hex 1f0).
:Hex2dec 1f0 Same ("0x" is optional in an argument).
:Hex2dec Converts all "0x" hex numbers to decimal in current line.
:'<,>'Hex2dec Same, for all visually selected text (v, V, or ^V).
:%Hex2dec Same, for all lines in buffer.

Converting strings

Following are some methods for working with percent-encoded text, and for showing ASCII characters in hex.

" Convert current line to percent-encoded hex for disallowed punctuation.
" Example: line "A/C[123]D\E" is converted to "A%2FC%5B123%5DD%5CE".
nnoremap <Leader>h :s@\([;(){}\[\]+ ,\-><\|=%&^\\/"']\)@\='%'.printf('%02X',char2nr(submatch(1)))@g<CR>
" Convert percent-encoded hex in current line to text (reverse of above).
nnoremap <Leader>H :s@%\(\x\x\)@\=nr2char('0x'.submatch(1))@g<CR>

" Convert each ASCII character in a string to hex bytes.
" Example: ":Str2hex ABC 123" displays "41 42 43 20 31 32 33".
command! -nargs=* Str2hex echo Str2hex(<q-args>)
function! Str2hex(arg)
  return join(map(split(a:arg, '\zs'), 'printf("%02x", char2nr(v:val))'))
endfunction

General functions

A script could use the following functions for conversions between decimal and hex.

" Return hex string equivalent to given decimal string or number.
function! Dec2hex(arg)
  return printf('%x', a:arg + 0)
endfunction

" Return number equivalent to given hex string ('0x' is optional).
function! Hex2dec(arg)
  return (a:arg =~? '^0x') ? a:arg + 0 : ('0x'.a:arg) + 0
endfunction

Using external programs

 TO DO 

  • The following is from old tip 772. It does not seem helpful, but we should discuss the menus somewhere so I am keeping the text for a while.

This example creates a menu for conversions using the bc calculator which is a standard utility on many Unix-based systems. Visually select the number (without leading '0x'), right click the selection, and select from the popup menu to transform the number.

vmenu 1.220 PopUp.&nr2hex <Esc>:exec("!echo \\"obase=16;".@*."\\" \| bc -l -q ")<CR>
vmenu 1.220 PopUp.hex&2nr <Esc>:exec("!echo \\"ibase=16;".toupper(@*)."\\" \| bc -l -q ")<CR>

More is needed to make it work. I had to do the following on a Linux system, but I suspect a setting regarding register * is also being used (it assumes that the selected text is in the * register).

set mousemodel=popup
vmenu 1.220 PopUp.&nr2hex <Esc>:exec '!echo "obase=16;'.@*.'" \| bc -l -q '<CR>
vmenu 1.220 PopUp.hex&2nr <Esc>:exec '!echo "ibase=16;'.toupper(@*).'" \| bc -l -q '<CR>

See also

Comments

 TO DO 

  • Check that new code works! (Will probably use this for next featured tip.)
  • Check that have covered all useful material from these old versions of tips: 27, 448, 772, 1076, 1479.

JohnBeckett 09:15, October 27, 2009 (UTC)


 TO DO 

  • Need a new title. Anything better than "Convert between hex and decimal"? JohnBeckett 09:26, October 27, 2009 (UTC)
I like "Convert between hex and decimal" or "Convert between number bases" or similar. In the tip, we should also mention the expression register for when you want to place the converted numbers in the text. For example, in insert mode, <C-R>=0x0a<Enter> will insert "10" and <C-R>=printf("0x%02x", 10)<Enter> will insert 0x0a. --Fritzophrenic 13:52, October 27, 2009 (UTC)
Advertisement