Vim Tips Wiki
Vim Tips Wiki
Advertisement
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
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 the reverse. A variety of methods are given, including some simple commands you can enter, and some scripts to easily replace hex numbers with decimal, or to replace decimal with hex. Handling percent-encoded text is also discussed, and there are links to tips showing how to edit a binary file in hex.

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 addition, the expression register can be used to enter converted numbers while typing. In insert mode, press Ctrl-R then = then the expression wanted, then press Enter. The value of the expression is inserted, and you will remain in insert mode. For example, <C-R>=0x09ab<Enter> will insert 2475, and <C-R>=printf('0x%04x',2475)<Enter> will insert 0x09ab.

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.

This version handles up to 32-bit long integers. An extended version of this script that works for arbitrary sized integers is available as a plugin on Github.

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

Sometimes one just needs to know the value of decimal/hexadecimal value, without changing the text. Put the following in your vimrc to define user command 'gn' to print the number under the cursor converted to hex/decimal (similar to built-in command 'ga' and 'g8' for ASCII character under the cursor):

nnoremap gn :call DecAndHex(expand("<cWORD>"))<CR>

function! DecAndHex(number)
  let ns = '[.,;:''"<>()^_lL]'      " number separators
  if a:number =~? '^' . ns. '*[-+]\?\d\+' . ns . '*$'
     let dec = substitute(a:number, '[^0-9+-]*\([+-]\?\d\+\).*','\1','')
     echo dec . printf('  ->  0x%X, -(0x%X)', dec, -dec)
  elseif a:number =~? '^' . ns. '*\%\(h''\|0x\|#\)\?\(\x\+\)' . ns . '*$'
     let hex = substitute(a:number, '.\{-}\%\(h''\|0x\|#\)\?\(\x\+\).*','\1','')
     echon '0x' . hex . printf('  ->  %d', eval('0x'.hex))
     if strpart(hex, 0,1) =~? '[89a-f]' && strlen(hex) =~? '2\|4\|6'
        " for 8/16/24 bits numbers print the equivalent negative number
        echon ' ('. float2nr(eval('0x'. hex) - pow(2,4*strlen(hex))) . ')'
     endif
     echo
  else
     echo "NaN"
  endif
endfunction

Numbers containing character A-F or prefixed with '0x', 'h' or '#' are treated as hexadecimal values:

WORD under cursor Output Description
32 32 -> 0x20, -(0xFFFFFFE0) decimal 32 in hex, decimal -32 in hex
-32 -32 -> 0xFFFFFFE0, -(0x20) decimal -32 in hex, decimal 32 in hex
0x32 0x32 -> 50 hex 32 in decimal
h'38 0x38 -> 56 hex 38 in decimal
#123 0x123 -> 291 hex 123 in decimal
0xFFFFFFE0 0xFFFFFFE0 -> -32 32 bit hex FFFFFFE0 in decimal
0xFFFE00 0xFFFE00 -> 16776704 (-512) hex FFFE00 in decimal, equivalent negative value on a 24 bits machine
ab 0xab -> 171 (-85) hex ab in decimal, equivalent negative value on a 8 bits machine

Using external programs

 TO DO 

  • Fix or delete this section.
  • 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>

For one of my recent Machine learning project UI, I had to create a hex to decimal converter in Javascript. You can use the following Javascript code: See hex to decimal working with Javascript

function hextodec() {
      var mm = document.getElementById("text_value").value;
      var x = new BigNumber(mm, 16);
      var dect = x.toString(10);
      document.getElementById("ans").innerHTML = dect;
     }

See also

Comments

Advertisement