5

I have a file containing nothing but integers and words, separated by arbitrary numbers of spaces, along the following lines:

1 alpha plural 1   0
6   1440
3 1 4 1 5 9 2 6 5 3 5 8 9
2 7 1 8 2 8 1 8 2 8 4 5 9
42   972 insert point here
16 7 88

But the software that a third party has written to read that file requires that it be floating point.

So, how can I add .0 to all the numbers, and leave the words and spacing intact?

2 Answers 2

6

I think the following substitution would be sufficient:

:%s/\<\d\+\>/&.0/g

The effect:

1.0 alpha plural 1.0   0.0
6.0   1440.0
3.0 1.0 4.0 1.0 5.0 9.0 2.0 6.0 5.0 3.0 5.0 8.0 9.0
2.0 7.0 1.0 8.0 2.0 8.0 1.0 8.0 2.0 8.0 4.0 5.0 9.0
42.0   972.0 insert point here
16.0 7.0 88.0
  • \d matches digits, & is the text that matched the whole pattern.
  • We use word boundaries (\< and \>) so that digits in the middle of a word are not affected.
6
  • Okay, that's better than my two-pass self-answer, you get the gong :-)
    – user579
    Feb 20, 2015 at 6:58
  • You could also have used \> to match the end of a word in place of the \+. (Only mentioning it because it's what popped into my head first, and it looks as though the OP might not know about \>.)
    – Rich
    Feb 21, 2015 at 8:42
  • @Rich Actually yes, that would be better combined with \+. /\<\d\+\>/ should keep digits in the middle of words safe.
    – muru
    Feb 21, 2015 at 8:43
  • @muru I'm not following you. /\d\>/ will already only match the digits at the ends of words.
    – Rich
    Feb 21, 2015 at 8:45
  • @Rich yes, and \<\d would take care of abc12.
    – muru
    Feb 21, 2015 at 8:48
1

You can actually do this in two passes, one to handle numbers at the end of the line and one to handle numbers followed by a space:

:g/\([0-9]\)$/s//\1.0/
:g/\([0-9]\) /s//\1.0 /g

The first simply finds a digit at the end of the line and replaces it with that digit and an additional .0.

It uses a capture group () to actually store the character that satisfied the search, and a reference \1 to use that stored character in the replacement text.

The second one is very similar but with the following changes.

  • It finds a digit followed by a space, rather than at the end of a line.
  • It incorporates the space into the replacement string.
  • It does it multiple times per line to change all integers, not necessary in the first case since there is only one end of line per line.

The result of running those two commands is, as requested:

1.0 alpha plural 1.0   0.0
6.0   1440.0
3.0 1.0 4.0 1.0 5.0 9.0 2.0 6.0 5.0 3.0 5.0 8.0 9.0
2.0 7.0 1.0 8.0 2.0 8.0 1.0 8.0 2.0 8.0 4.0 5.0 9.0
42.0   972.0 insert point here
16.0 7.0 88.0

Now be aware that you can actually do this with the s command rather than g, I prefer the latter since you don't have to specify lines and it allows you to carry out much more powerful actions (the s part of the g command can be replaced with other more powerful commands, rather than just substitute).

If you don't want to use g for some reason, you can do this instead:

:1,$s/\([0-9]\)$/\1.0/
:1,$s/\([0-9]\) /\1.0 /g

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.