Vim incorrectly removes zeros when decrementing - vim

Vim removes zeros from in front of some digits when decrementing:
If I take a text file with the following:
a02
a03
a04
a05
a06
a07
a08
a09
a10
a11
And use ctrl+V to highlight the second and third columns, and then hit ctrl+X to decrement, I am left with:
a01
a02
a03
a04
a05
a06
a7
a8
a9
a10
I am running Vim version 7.4.1689 and I loaded it without my .vimrc via
$ vim -u NONE

This is happening because Vim will automatically recognize and convert octal values.
From the help (:h variables):
Conversion from a Number to a String is by making the ASCII representation of
the Number.
Examples:
Number 123 --> String "123"
Number 0 --> String "0"
Number -1 --> String "-1"
Conversion from a String to a Number is done by converting the first digits to
a number. Hexadecimal "0xf9", Octal "017", and Binary "0b10" numbers are
recognized. If the String doesn't start with digits, the result is zero.
Examples:
String "456" --> Number 456
String "6bar" --> Number 6
String "foo" --> Number 0
String "0xf1" --> Number 241
String "0100" --> Number 64
String "0b101" --> Number 5
String "-8" --> Number -8
String "+8" --> Number 0
Your values 02 through 07 are being recognized as valid octal values and preserved as such, decremented to octal 01 through 06.
When you reach 08 it is not a valid octal value. It is treated as the string 08, converted to decimal value 8, and decremented to 7. This happens again with 09, which ends up being 8.
The 10 and 11 values are decremented as decimal as well. Because 10 was decimal, not octal, you don't get a leading 0 in the resulting 9 value.
I'm not aware of a way to do what you want with the decrement command.
EDIT: After finding this answer, I tested this expression and it does what you are trying to do in this specific case:
:%s/\v[0-9]+/\=printf("%02d", substitute(submatch(0), '^0\+', '', 0)-1)/
I'm not sure whether this solves your general use case, because it's quite different from the original operation using a selection. But for the file you provided, it achieves the result you were after.
Dissecting this a bit to explain it:
First we start by calling the global sub command %s and passing the \v flag to turn on "very magic" mode. This may or may not change the behavior depending on your settings, but this is a public example, so it is included here to ensure that mode is active.
:%s/\v
Then, we find all the contiguous sequences of digits. This will find 02, 03, and so on from your example.
[0-9]+
Then in the replacement portion we have this command, which does the real work:
\=printf("%02d", substitute(submatch(0), '^0\+', '', 0)-1)
The substitute() function determines what the new value is. submatch(0) means to use the entire match. Using a pattern of ^0\+ and a replacement of (empty string) says to strip the leading zero from any number which has one. The 0 at the end isn't too important; it just says there are no flags to the substitute() function.
The result of the substitute command is a number. Say 02 has been stripped down to be 2. Using the - 1 at the end, we subtract 1 from that result (decrement).
Finally, this result is passed to the printf function. Using a format string %02d says to print the values as decimal, in 2-digit wide format, padding with leading zeroes.

If you want Vim to treat all numbers as decimals, you may want to add the following line to your .vimrc:
set nrformats=

Related

How to convert a string to number in scheme without removing the leading zero?

I want to convert a string to a number in Scheme, but when I use the function string->number it removes the leading zero
For example
(string->number "01") gives me 1
Is there a way to convert the string so that it doesnt remove the leading zero and gives me 01 instead?
You can't: leading zeros are just part of the written representation of numbers, not part of the number itself. In particular 01, 1 and 00000001 are all the same number.
If you want to print numbers with leading zeros, for instance to line things up, then there are utilities which do that. For instance in Racket, while the format / printf family of procedures cannot do this, the procedures provided by racket/format can:
> (require racket/format)
> (~a 1 #:width 2 #:align 'right #:pad-string "0")
"01"
However you will still need to deal with negative numbers yourself, which is rather annoying.

ASCII text to Hexadecimal in Excel

I want to this but i don't know what to do, the only functions it seems to be useful is "DEC.TO.HEX".
This is the problem, i have in one cell this text:
1234
And in the next cell i want the hexadecimal value of each character, the expected result would be:
31323334
Each character must be represented by two hexadecimal characters. I don't have an idea how to solve this in excel avoiding make a coded program.
Regards!
Edit: Hexadecimal conversion
Text value Ascii Value (Dec) Hexadecimal Value
1 49 31
2 50 32
3 51 33
4 52 34
Please try:
=DEC2HEX(CODE(MID(A1,1,1)))&DEC2HEX(CODE(MID(A1,2,1)))&DEC2HEX(CODE(MID(A1,3,1)))&DEC2HEX(CODE(MID(A1,4,1)))
In your version you might need the .s in the function (and perhaps ;s rather than ,s).
DEC2HEX may be of assistance. Use, as follows:
=DEC2HEX(A3)
First split 1234 to 1 2 3 4 by using MID(), then use Code() for each character, and then again concentate. Below is the formula, Y21 is the cell in which 1234 is written
=CONCATENATE(CODE(MID(Y21,1,1)),CODE(MID(Y21,2,1)),CODE(MID(Y21,3,1)),CODE(MID(Y21,4,1)))
1234 >> 49505152

How do I convert a 64bit number to hexadecimal in excel?

I'm trying DEC2HEX(1000000000050000000) but it comes out as #NUM! as the number is too large for this function.
Is there another function I could use to turn this number into hexadecimal?
If you want to convert a decimal number to a 64 bit hex string, assuming that the decimal number is in cell A1 you can use the following:
=CONCATENATE(DEC2HEX(A1/2^32),DEC2HEX(MOD(A1,2^32),8))
This will work up to decimal value of 18,446,744,073,709,500,000 or hex value of 0xfffffffffffff800.
Bonus:
To convert from hex string to decimal, assuming that the 64bit hex string is in cell A1 and contains 16-characters then you can use the following:
=HEX2DEC(LEFT(A1,8))*2^32+HEX2DEC(RIGHT(A1,8))
You can adjust the number of characters in the LEFT(text,[num_chars]) to better suit your needs.
If your hex string has a 0x then you can use the following:
=HEX2DEC(MID(A1,3,8))*2^32+HEX2DEC(RIGHT(A1,8))
I found a simple solution for converting HEX to DEC and vice versa without the limits of characters.
HEX to DEC: use DECIMAL(input number or cell coordinates, input base number)
Case 1: I want to convert hex value "3C" to decimal, the formula is DECIMAL(3C, 16).
Case 2: I want to convert binary value "1001" to decimal, the formula is DECIMAL(1001, 2).
DEC to HEX: use BASE(input number or cell coordinates, output base number)
Case 1:I want to convert number value "1500" to hexadecimal, the formula is BASE(1500, 16)
Case 2:I want to convert number value "1500" to binary, the formula is BASE(1500, 2)
The DEC2HEX function has a limit of 549,755,813,887, try this formula it works for numbers up to 281,474,976,710,655.
=DEC2HEX(A7/(16^9),3)&DEC2HEX(MOD(A7,16^9),9)
There is a free add-in available that will handle that: Xnumbers
Seems to work OK:
=cvDecBase("1000000000050000000",16) --> DE0B6B3AA5EF080
Long formula but it is working for 64-HEX characters:
=HEX2DEC(MID(A24,1,8))*2^512 *(4) +HEX2DEC(MID(A24,9,8))*2^512 *(2) +HEX2DEC(MID(A24,17,8))*2^512+HEX2DEC(MID(A24,25,8))*2^256+HEX2DEC(MID(A24,33,8))*2^128+HEX2DEC(MID(A24,41,8))*2^64+HEX2DEC(MID(A24,49,8))*2^32+HEX2DEC(MID(A24,57,8))
please note: (*4) = *4 (remove brackets) and: (*2) = *2 (remove brackets)
also note: all 64 character must be present like the following example:
0000000000000000000000000000000000000000000000000000000000000fd1

Python 3 string formatting with filler more than one character long

I am attempting to format a string in such a way, that I can make a repeating sequence of numbers an arbitrary length.
I've been looking at these examples: How do I format a number with a variable number of digits in Python? and String Formatting in Python 3.
Here's what I tried to do:
print("{0:{1}{2}d}".format(0, 0, 8))
will result in eight pretty 0's all in a row like so: 00000000
but attempting to change the second argument from 0 to 25
print("{0:{1}{2}d}".format(0, 25, 8))
Results in an a single 0 that is as far right as it can go in my console instead of 25252525 So I think the issue is using a string with more than one character as filler instead of a single character.
The specification for string formatting goes like this:
format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]
In this case, we're only interested in the [0][width] part. [0] is an optional parameter which pads numbers with zeros, so you can format 4 as '004'. [width] specifies the total width of the field.
When you write:
print("{0:{1}{2}d}".format(0, 0, 8))
It becomes:
print("{0:08d}".format(0))
Which is a 0 padded with zeroes up to a length of 8: 00000000.
However, your other example:
print("{0:{1}{2}d}".format(0, 25, 8))
Becomes:
print("{0:258d}".format(0))
Which is a 0 padded with spaces (because there is no 0 in the formatter) up to a length of 258.
I think string formatting is not suited to solve your problem. You can use other fill characters than 0 (using the [fill] option in the formatting spec), but it can't be more than one character.
The simplest way to get what you want is probably this:
>>> print((str(25) * 8)[:8])
25252525

Increment and decrements numbers

I have this text with numbers:
My numbers are 04, and 0005
My numbers are 05, and 0006
My numbers are 06, and 0035
My numbers are 07, and 0007
My numbers are 08, and 0009
This is the code I always used to increment or decrement numbers in a selection/block selection/column:
p.e. increment the last 4 numbers in above text with 8:
'<,'>s/\%V\<\d\{4}\>/\=submatch(0)+8/g
but I noted today that it does strange things.
This is the output:
My numbers are 04, and 13
My numbers are 05, and 14
My numbers are 06, and 37 <---
My numbers are 07, and 15
My numbers are 08, and 17
it removes the leading zero's ( I would like to keep them if there are leading zero's
and not add them if there aren't leading zero's)
it added 8 to all numbers except 37, where it added 2. (why?)
Can anyone help me to find a regex to add /subtract numbers
from selection (or block selection) without losing the leading zero's?
note:
I noted that Control A + Control x keeps the leading zero's and does the work as I want but:
- I've seen that it can not be used in a substitute command ('<,'>s/)
- and I don't know how to add p.e. 200 to a list of numbers (200 x ?)
leading zero makes number 8-based.
(0035)8 == (29)10
You can test in vim:
:echo 0035 == 29
It'll print 1(true).
Try this:
:%s/\(\<[0-9]\{4}\>\)\#=0*\([0-9]*\)/\=submatch(2)+8/
this?
:%s/\v[0-9]{4}/\=printf("%04d", substitute(submatch(0), '^0\+', '', 0)+8)/
EDIT
#Remonn, you should give the right sample input in your question. the line above works on your example.
for your new requirement, take a look the line below:
input:
40
20
120
0500
230
0000000020
00000000000005000
vim cmd:
:%!awk '{if($0~/^0/){f="\%"length($0)"d";$0+=8; s=sprintf(f,$0); gsub(/ /,"0",s);}else s=$0+8;print s}'
will change the file to:
48
28
128
0508
238
0000000028
00000000000005008
in my cmd, I used '%', you can select (v) the numbers you want to do tricks with, then try with my cmd.
good luck
By default, Vim treats numbers beginning with 0 as octal.
For this reason I have this in my .vimrc:
set nrformats-=octal " Don't bother with octal, I never use it

Resources