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
- Improved hex editing
- Hex dump
- ConvertBase plugin to convert to/from various numeric bases
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)