0

I have a file with text and numbers in it like this

had   hdb   hdc
1.5   -.3   4.6
2.0   7.1   .09
.17   7.4   8.9

So for those numbers without a leading zero before decimal points, how can I add those zeros back with a simple one line command?

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
zhihao_li
  • 183
  • 10

6 Answers6

4

One option would be to use a sed substitution:

sed -E 's/(^|[^0-9])\./\10./g' file

Match (and capture) the start of the line or any non-digit followed by a .. Replace with the captured part \1 followed by 0.:

had   hdb   hdc
1.5   -0.3   4.6
2.0   7.1   0.09
0.17   7.4   8.9
Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
3

Search for a decimal proceeded by a non-number and followed by a number globally (the g flag), and replace it with that same pattern (\2 part) but with a 0 in front of the decimal.

sed 's/\([^0-9]\|^\)\(\.[0-9]*\)/\10\2/g' input.txt

Output:

had   hdb   hdc
1.5   -0.3   4.6
2.0   7.1   0.09
0.17   7.4   8.9
Jacek Trociński
  • 882
  • 1
  • 8
  • 23
1

With perl which supports lookarounds

$ perl -pe 's/(?<!\d)\./0./g' file 
had   hdb   hdc
1.5   -0.3   4.6
2.0   7.1   0.09
0.17   7.4   8.9
  • (?<!\d)\. match . which is not preceded by a digit
  • 0. for such matches, add a 0 before
Sundeep
  • 23,246
  • 2
  • 28
  • 103
0

As the awk printf modifiers are a mystery to me every time I use them, I just had to give it a go:

$ awk '
{
    for (i=1; i<=NF; i++)                          # for each field
        if($i ~ /[-\.0-9]+/)                       # if looks like a number
            printf "%5.2g%s", $i, (i<NF?OFS:ORS);  # print one way
        else 
            printf "%5s%s", $i, (i<NF?OFS:ORS)     # else the other way
}' file
  had   hdb   hdc
  1.5  -0.3   4.6
    2   7.1  0.09
 0.17   7.4   8.9

The only visible flaw is 2.0 getting evened to 2 (3rd record, 1st field). Is there a way to fix that?

James Brown
  • 36,089
  • 7
  • 43
  • 59
  • I also tried to solve this using AWK. It is easy, if we are allowed to replace `OFS`. But what if we want to only replace the numbers in the original rows, i.e. to preserve the original spaces as much as possible? – Ruslan Osmanov Nov 24 '16 at 14:20
  • @Ruslan the best way to preserve the structure of the individual fields and the spaces between them is not to touch them at all, i.e. to use a global substitution on the whole line. This is why I chose to use `sed` this time :) – Tom Fenech Nov 24 '16 at 14:26
  • @RuslanOsmanov I solved it now with `printf` modifiers but it ain't no one-liner nor a beauty. – James Brown Nov 24 '16 at 14:30
  • 1
    The OPs presumed desired output (which he hasn't shown us btw!) would be neither in %f nor %g format so converting with either of those just changes the problem since you'd still have another sub() of some kind to do afterwards. There is no canned solution using printf formatting since the OP wants their data in a non-uniform format. – Ed Morton Nov 24 '16 at 15:20
0

Perl version:

perl -pe 's/([\d\.-]+)/$1 < 1 ? $1 + 0 : $1/ge' file

Output:

had   hdb   hdc
1.5   -0.3   4.6
2.0   7.1   0.09
0.17   7.4   8.9
Ruslan Osmanov
  • 20,486
  • 7
  • 46
  • 60
0

Why doesn't the first sub work on .09?

awk '{sub(/^\./,"0.")sub(/-/,"-0")sub(/\.09/,"0.09")}1' file

had   hdb   hdc
1.5   -0.3   4.6
2.0   7.1   0.09
0.17   7.4   8.9
Claes Wikner
  • 1,457
  • 1
  • 9
  • 8