Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Issue getting value from text file and keep decimal

by jason.jackal (Novice)
on Jun 26, 2017 at 14:07 UTC ( [id://1193569]=perlquestion: print w/replies, xml ) Need Help??

jason.jackal has asked for the wisdom of the Perl Monks concerning the following question:

Folks I am trying to make an application that will loop over each line in a text file, and format output. However, the first line is dropping the decimal. Looking for some ideas on how to fix this and explain what is going on. I created my working copy in Python; however, I really want to learn Perl over Python.
#!/usr/bin/perl #checkbook #2017-06-20 ## This app will create a general ledge sub format_value { local $_ = shift; 1 while s/^([-+]?\d+)(\d{3})/$1,$2/; return $_; } $item_date = "DATE"; $item_description = "DESCRIPTION"; $item_account = "ACCOUNT"; $item_debit = "DEBIT"; $item_credit = "CREDIT"; $item_balance = "BALANCE"; $blank_debit = " "; $blank_credit = " "; open (file_read, "input-checkbook.txt"); open (file_write, ">checkbook.txt"); sub runScript { $main_balance = 0.00; $format_main_balance = sprintf("%.2f",$main_balance); while ($line = <file_read>) { @fields = split /,/, $line; chomp(@fields); $date = @fields[0]; $description = @fields[1]; $length_description = length($description); if ($length_description > 40) { $description = substr $description, 0, 40; substr($description,-1) = "~"; } else { $description = @fields[1]; } if (@fields[2]){ $debit = @fields[2]; #$debit_decimal = sprintf("%.2f",$debit); $format_debit = format_value($debit); $main_balance = $main_balance - $debit; #sprintf file_write "%s\n", $l_format_main_balance; $format_main_balance = format_value($main_balance); #$format_main_balance = sprintf("%.2f",$format_main_balance); printf file_write "%-11s %-41s %10s %11s %11s\n", @fields[0], $d +escription, $format_debit, $blank_credit, $format_main_balance; } else { $credit = @fields[3]; #$credit = sprintf("%.2f",$credit); $format_credit = format_value($credit); $main_balance = $main_balance + $credit; $format_main_balance = format_value($main_balance); #$format_main_balance = sprintf("%.2f",$format_main_balance); printf file_write "%-11s %-41s %10s %11s %11s\n", @fields[0], $d +escription, $blank_debit, $format_credit, $format_main_balance; } } } printf file_write "%-11s %-41s %-11s %-11s %-10s\n",$item_date,$item_d +escription,$item_debit,$item_credit,$item_balance; printf file_write "=================================================== +=====================================\n"; runScript(); close(file_read); close(file_write); exit;
Text file
2017-05-01,starting balance to track character count,,900000.00 2017-05-01,phone bill dsfsdfsfdsfsfsfsdfsfsfsfsfdfsdfsfsfsfsf,300000.0 +0, 2017-05-03,Water,100000.34, 2017-05-05,Electric Bill,900.21, 2017-06-03,debit 45678901dfsf2345678901234567890ddddddddddddd,30.32 2017-06-03,12345678901234567890123456789034,,30.98 2017-06-03,credit 8901234567890123456789034567890123,,30.98 2017-06-03,credit dfdfd01234567890123456789034567890123,,30.98 2017-06-08,Food,23.00, 2017-06-12,Cash,20.00,

Replies are listed 'Best First'.
Re: Issue getting value from text file and keep decimal
by Eily (Monsignor) on Jun 26, 2017 at 14:53 UTC

    The issue is that you go back and forth between number and string representation. In $main_balance = $main_balance - $debit; the minus is a numeric operation, so perl translates your string into numbers, where the number of displayed digits is not memorized. Your format function turns it back into a string, but the formatting already has been lost.

    I think your best option is Number::Format, which will output the expected format wheter the input is already a number, or a string representation (if the string doesn't already includes thousands separator, "900,000" will be interpreted as the number 900).

    Also the sigil @ is used to fetch several elements, and $ a single one. So even if you are using a single element from an array, $ has to be used (see perldata). The second element of the array @fields should therefore be $fields[1] instead. Perl will actually complain about this if warnings are activated (which they should be).

    Edit: turned $fields1 into $fields[1], thanks AnomalousMonk

      HI Eily, Thank you for your help, but I am a little confused. I thought I declaring a decimal/float with 0.00 already. And when the loop goes and reads in 900000.00 it is already reading in another decimal or float. The was my thinking anyway, and why I thought I had to change in a decimal/float to a string so I could insert the comma. The idea was to keep the math and decimal in one variable and write out the product to a string.

        The two digits after the decimal points are part of the formatting of the string, but a float contains only the value, without any concept of format or display. So when perl has to extract the value from the string "900000.00" to be able to make mathematic operations on it (the substraction), the formatting information is lost.

        The confusion might come from the fact that you think you have a float in the first place, when you have instead a string, because perl will (edit: almost) seemlessly turn one into another to make life easier for you, so although your $main_balance is a string before $main_balance = $main_balance - $debit;, it will have been replaced by a number after that line.

Re: Issue getting value from text file and keep decimal
by Discipulus (Canon) on Jun 26, 2017 at 14:33 UTC
    Hello jason.jackal and welcome to the monastery and to the wonderful world of Perl!

    Just some general advice for the moment:

    Always, and this means ALWAYS use strictures at top of the program:

    use strict; use warnings;

    If you do not understand messages produced by use warnings you add use diagnostics; and later on commenting it.

    Doing so you are forced to declare variables, and doing so you are forced to think about the visibility scope you give them. So;

    # $item_date = "DATE"; # becomes my $item_date = "DATE";

    Then prefere and use lexical filehandle instead of bareword ones (anyway bareword form is used UPPERCASE). Always put the mode for opening even if < can be omitted. Check if the operation succeded. Always close explicitly your filehandle when you do not need them anymore. So:

    # open (file_read, "input-checkbook.txt"); # becomes open my $read, '<', $filepath or die "impossible to read from [$filepa +th]!"; .. close $read;

    You can use autodie; if you want to write less.

    After all this important things even if not pertinent to your problem.. it is by far better to reduce the code you sumbit for review to isolate the presumed error you encounter..

    My time is finished for now..

    welcome!

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      Thank you for telling me about warnings. This has helped me troubleshoot some of my other scripts that I am tying to build and learn.
      Thank you for your replay. I have not learned about the "my" or strict yet. Why do you need those? I do not understand the concept. Thank you
        take your free copy of ModerPerl the free book and get scope explained at page 80.. but be sure to read pages 1-79 before!

        Read good perl sources to write good code!

        have fun!

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
        I have not learned about the "my" or strict yet. Why do you need those?

        I think the page Use strict and warnings explains this pretty well.

Re: Issue getting value from text file and keep decimal
by toolic (Bishop) on Jun 26, 2017 at 14:25 UTC
    UPDATE2: You were close. You want to set the decimal places to 2 values before you add commas. See also Number::Format. This works for me:
    $format_main_balance = format_value(sprintf("%.2f",$main_balance +));

    UPDATE1: I just read-read your question, and I now see the decimal dropped for 900,000.

    OLD... IGNORE: When I run your code, it seems to keep decimals. Here is the output I get:

    DATE DESCRIPTION DEBIT CRED +IT BALANCE ====================================================================== +================== 2017-05-01 starting balance to track character cou~ 900, +000.00 900,000 2017-05-01 phone bill dsfsdfsfdsfsfsfsdfsfsfsfsfdf~ 300,000.00 + 600,000 2017-05-03 Water 100,000.34 + 499,999.66 2017-05-05 Electric Bill 900.21 + 499,099.45 2017-06-03 debit 45678901dfsf2345678901234567890dd~ 30.32 + 499,069.13 2017-06-03 12345678901234567890123456789034 + 30.98 499,100.11 2017-06-03 credit 89012345678901234567890345678901~ + 30.98 499,131.09 2017-06-03 credit dfdfd012345678901234567890345678~ + 30.98 499,162.07 2017-06-08 Food 23.00 + 499,139.07 2017-06-12 Cash 20.00 + 499,119.07

    Do you get a different output? If so, post exactly what you get. I'm using Perl version 5.16.3.

    Basic debugging checklist

      Thank you for your reply. Notice how the first like is dropping the decimal. 900,000.00 credit in but only showing 900,000 as the balance field. Thank you
        You may have missed my second update. It now works for me as expected when I use this code in 2 places:
        $format_main_balance = format_value(sprintf("%.2f",$main_balance +));
        DATE DESCRIPTION DEBIT CRED +IT BALANCE ====================================================================== +================== 2017-05-01 starting balance to track character cou~ 900, +000.00 900,000.00 2017-05-01 phone bill dsfsdfsfdsfsfsfsdfsfsfsfsfdf~ 300,000.00 + 600,000.00 2017-05-03 Water 100,000.34 + 499,999.66 2017-05-05 Electric Bill 900.21 + 499,099.45 2017-06-03 debit 45678901dfsf2345678901234567890dd~ 30.32 + 499,069.13 2017-06-03 12345678901234567890123456789034 + 30.98 499,100.11 2017-06-03 credit 89012345678901234567890345678901~ + 30.98 499,131.09 2017-06-03 credit dfdfd012345678901234567890345678~ + 30.98 499,162.07 2017-06-08 Food 23.00 + 499,139.07 2017-06-12 Cash 20.00 + 499,119.07
      Hi, Let me ask you this. I am not always able to install applications on machines I use, and due to the latter I will be looking at methods to port my perl script to an EXE file. If I use a library/module from CPAN will that library or module compile to EXE on with my script so I just need a few files? Thank you - never used CPAN before. Much appreciated. Thank you JJ
Re: Issue getting value from text file and keep decimal
by Anonymous Monk on Jun 27, 2017 at 15:59 UTC
    The Perl language contains only a generic floating-point data type with no control over the number of digits to the right of the decimal point nor control over rounding and formatting ... sprintf() gives you very limited control over appearance.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1193569]
Approved by Discipulus
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2024-03-29 01:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found