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.

  • post the expected output... – Avinash Raj Sep 5 '14 at 12:42
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
  • 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 '14 at 12:48
  • @terdon yep. I though that was an expected ouput. Later that only i realized.. – Avinash Raj Sep 5 '14 at 12:52
  • @Kasra do you know which one op wants? – Avinash Raj Sep 5 '14 at 12:54
  • @AvinashRaj: The sed can be sed -e 's/\([^,]*\)-/-\1/g' – cuonglm Sep 5 '14 at 16:17
  • @AvinashRaj yep ... im sorry i misunderstood the op's request ! – Kasrâmvd Sep 5 '14 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'
    

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.