3

I have a huge csv file which has - (Minus) sign at the end of numbers. Now I need to move these - minus signs to begin of the numbers, i.e I need to remove the last character if it has '-' sign and put the '-' sign to the front.

0.00,70440.19-,18.31-,0.00,451.59-,13788.77-,44.19-,6289.29-
1.03-,39.24-,0.11-,16.96-,0.00,72377.70-,0.00,146673.67-,59.11-,0.00

I tried the below one but if there is decimal value '.' character, then it adds the minus sign before that:

perl -pe 's#(\d{1,})(-)#$2$1#'g  file

output is below:

0.00,70440.-19,18.-31,0.00,451.-59,13788.-77,44.-19,6289.-29
1.-03,39.-24,0.-11,16.-96,0.00,72377.-70,0.00,146673.-67,59.-11,0.00

Please suggest any awk / sed / perl one liner to do this job?

Regards, Vino.

1
  • post the expected output... Sep 5, 2014 at 12:42

4 Answers 4

1

The below one worked: Any other awk or sed solution would be great to know...

perl -pe 's#(\d{1,}[.]\d{1,})(-)#$2$1#'g  file
1

Same as perl command,

$ sed 's/\([0-9]\+\.[0-9]\+\)-/-\1/g' file
0.00,-70440.19,-18.31,0.00,-451.59,-13788.77,-44.19,-6289.29
-1.03,-39.24,-0.11,-16.96,0.00,-72377.70,0.00,-146673.67,-59.11,0.00

Another perl one-liner,

$ perl -pe 's/([^,\n]*?)-/-\1/g' file
0.00,-70440.19,-18.31,0.00,-451.59,-13788.77,-44.19,-6289.29
-1.03,-39.24,-0.11,-16.96,0.00,-72377.70,0.00,-146673.67,-59.11,0.00
5
  • Please don't delete your answers like that. The downvote was mine and I would have left a comment if you had waited. Your sed solution was wrong and gave the wrong output, 451.-59 instead of -451.59 for example. I would have retracted the vote if you'd fixed it. Also, why are you escaping the +? And why are you assuming that all numbers will have decimals? This approach will fail on 45- for example.
    – terdon
    Sep 5, 2014 at 12:48
  • @terdon yep. I though that was an expected ouput. Later that only i realized.. Sep 5, 2014 at 12:52
  • @Kasra do you know which one op wants? Sep 5, 2014 at 12:54
  • @AvinashRaj: The sed can be sed -e 's/\([^,]*\)-/-\1/g'
    – cuonglm
    Sep 5, 2014 at 16:17
  • @AvinashRaj yep ... im sorry i misunderstood the op's request !
    – Mazdak
    Sep 5, 2014 at 16:19
1

Another perl

perl -F, -lane 'print join ",", map {(/-$/ && chop) . $_} @F' file
0

Here are a few:

  1. A shorter perl one

    perl -pe 's/([\d.]+)-/-$1/g' file 
    
  2. (GNU) sed

    sed -r 's/([0-9.]+)-/-\1/g' file 
    
  3. Any sed

    sed 's/\([0-9.]*\)-/-1\1/g' file 
    
  4. Gawk. Note that the various awk variants are not very good at tasks that involve capturing patterns. GNU awk (gawk) and others can do it but I would use one of the solutions above instead.

    gawk -F, '{
                for(i=1; i<NF; i++){
                    if(sub(/-/,"",$i)){printf "-%s,",$i}
                    else{printf "%s,",$i}
                }
                if(sub(/-/,"",$NF)){print "-"$NF}
                else{print $NF} }' file 
    

    I am sure there must be a better awk way of doing it but the above will work despite being ugly and cumbersome.

  5. Needlessly complex

    perl -pe 's/\n/\n\n/; s/,/\n/g; ' file | 
        awk -F"-"  '/-/{printf "-";}{print $1}' | 
            perl -000ne 's/\n./,/g;s/\n\n/\n/g; print'
    

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .