Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

regex and string functions help needed.

by valavanp (Curate)
on Oct 25, 2006 at 12:04 UTC ( #580554=perlquestion: print w/ replies, xml ) Need Help??
valavanp has asked for the wisdom of the Perl Monks concerning the following question:

i have used the code given by corion for the problem which i faced. I have tested with some values and the results of them are:
Input Output Through Code Expected Output. 4ABC 8.432 11.93544 2A2B2C 8.644 23.87 3C 4.5 4.5 ABC 4.322 2.98386
Only 1 value is coming correct. Other values are showing some discrepancies. I am attaching the code below:
$a="ABC"; $b=length($a); print "$b\n"; for($i=0;$i<$b;$i++){ $a=~s/(\d+)(.)/$2 x $1/ge; } print "$a\n"; my %value = ( A => 2.74, B => 2.64, C => 2.5, ); my %factor = ( A => 50/100, B => 55/100, C => 60/100, ); my @letters = split //, $a; my $result = 0; my $temp=0; for my $letter (@letters) { $result=$result + $value{ $letter }* $factor{ $letter }; #print "$result\n"; }; print $result;

Comment on regex and string functions help needed.
Select or Download Code
Re: regex and string functions help needed.
by Corion (Pope) on Oct 25, 2006 at 12:13 UTC

    That is because my code doesn't do what you want.

    I stated the equation that my code calculates and you said that the calculation wasn't what you want. So it's not really a surprise that my code gives results that are different from what you want. Maybe you should restate what you want, and also what my code does, so somebody willing to hold your hand can then change my code for you to solve your homework.

      Corion, i used your code because i couldn't understand the replies given my holli and swamy_rio. I am able to understand your code better than mine and others. That's why i posted that. Since you advised me not to use if else constructs in my code, i didn't use that. The only solution i got is from your reply. So please forgive me if anything wrong done to you. Thanks.
Re: regex and string functions help needed.
by davorg (Chancellor) on Oct 25, 2006 at 12:36 UTC
Re: regex and string functions help needed.
by Samy_rio (Vicar) on Oct 25, 2006 at 13:15 UTC

    The below code is developed based on your logic and I am getting the following output. But I am not getting your expected output. Check whether your expected output is correct.

    use strict; use warnings; my %p = (A => 2.74, B => 2.64, C => 2.5); my @range = (50,55,60,65,70,75,80,85,90); while(my $str = <DATA>){ chomp($str); print "\nInput : $str\n"; $str =~ s/(\d+)(\w)/($2 . '*') x $1/eg; $str =~ s/(\w)(\w)/$1 . '*' . $2 . '*' /eg; $str =~ s/(?!\*)$/*/; $str =~ s/(.)\*(?!\1)/"$1\*\(".$range[ord($1) - 65]."\/100\)\*"/eg +; $str =~ s/\*+$//; $str =~ s/$_/$p{$_}/g for (keys %p); print "Expression: ".$str ."\n"; print "Output : ",eval$str ,"\n\n"; } __DATA__ 4ABC 2A2B2C 3C ABC Output is: Input : 4ABC Expression: 2.74*2.74*2.74*2.74*(50/100)*2.64*(55/100)*2.5*(60/100) Output : 61.38045890064 Input : 2A2B2C Expression: 2.74*2.74*(50/100)*2.64*2.64*(55/100)*2.5*2.5*(60/100) Output : 53.96012424 Input : 3C Expression: 2.5*2.5*2.5*(60/100) Output : 9.375 Input : ABC Expression: 2.74*(50/100)*2.64*(55/100)*2.5*(60/100) Output : 2.98386

    Regards,
    Velusamy R.


    eval"print uc\"\\c$_\""for split'','j)@,/6%@0%2,`e@3!-9v2)/@|6%,53!-9@2~j';

      My code in Re^3: string functions (in valavanp's original thread) gets to the same results - so we have both understood our fellow monk incorrectly (?) but in the same way :)

      Update: So, valavanp, it would really help if you could spell out for us step by step how you arrive at your expected values ...

      -- Hofmator

      Code written by Hofmator and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re: regex and string functions help needed.
by doowah2004 (Monk) on Oct 25, 2006 at 13:58 UTC
    valavanp, I think this is what you wanted:
    $a="ABC"; $b=length($a); print "$b\n"; for($i=0;$i<$b;$i++){ $a=~s/(\d+)(.)/$2 x $1/ge; } print "$a\n"; my %value = ( A => 2.74, B => 2.64, C => 2.5, ); my %factor = ( A => 50/100, B => 55/100, C => 60/100, ); my @letters = split //, $a; my $result = 1; my $temp=0; for my $letter (@letters) { $result *= $value{ $letter }; #print "$result\n"; }; my %seen; my @uniqed = grep !$seen{$_}++, @letters; for my $letter (@uniqed) { $result *= $factor{ $letter }; #print "$result\n"; }; print $result;
    *UPDATE*
    I did not refresh my browser before I posted, it appears the two post before this get the same results...
Re: regex and string functions help needed.
by holli (Monsignor) on Oct 25, 2006 at 16:47 UTC
    valanp,
    first of all, you have changed the original content of your node without leaving notice. This will confuse future readers. Please don't do that.

    As for your problem: next time please include complete sample data and input/expected output specs. In your OP there was only one special case.

    Anyway, here is a subroutine for you that solves your problem:
    use warnings; use strict; use Data::Dumper; my %value = ( A => 2.74, B => 2.64, C => 2.5, ); my %factor = ( A => 50/100, B => 55/100, C => 60/100, ); sub calc { # fetch arguments my $expression = shift; my $values = shift; my $factors = shift; # build an array of normalized terms # (normalize = replace non existant factors by 1) # as in 4ABC => 4A 1B 1C my @term; while ( $expression =~ /([0-9]*)([A-Z])/g ) { push @term, [$1?$1:1, $2]; } # now iterate over that array and do the # calculation my $result = 1; $result *= $_->[0] * $values->{$_->[1]} * $factors->{$_->[1]} for @term; return $result; } print calc ("4ABC", \%value, \%factor), "\n"; print calc ("2A2B2C", \%value, \%factor), "\n"; print calc ("3C", \%value, \%factor), "\n"; print calc ("ABC", \%value, \%factor), "\n";


    holli, /regexed monk/
Re: regex and string functions help needed.
by chargrill (Parson) on Oct 25, 2006 at 23:19 UTC

    velanvp: I'm not sure the rest of your code does what you want, as your specifications are all over the place. However, near the end, you could try changing this:

    my $result = 0; my $temp=0; for my $letter (@letters) { $result=$result + $value{ $letter }* $factor{ $letter }; #print "$result\n"; };

    Change $result to be initialized as 1, and change the assignment to $result inside your for loop to use the *= operator. And get rid of $temp - it doesn't look like you're using it. The result will look like this:

    my $result = 1; for my $letter (@letters) { $result *= $value{ $letter } * $factor{ $letter }; };

    If that doesn't work, or if you're still having trouble understanding what you're doing, see if you can understand the following any easier ( which has been Updated: replaced pop @divisors with shift @divisors, fixed output to match updated code. )

    #!/usr/bin/perl use strict; use warnings; sub calc { my $string = shift; my %p = ( A => 1.5, B => 2.5, C => 3.5, ); # in another thread, he indicated this was the series he needed my @divisors = ( 50/100, 55/100, 60/100, 65/100, 70/100, 75/100, 80/100, 85/100, 90/100 ); my $result = 1; # in another thread, he said he needed to match A,B,C,D,E,F,G,H an +d J my @substrings = $string =~ /(\d{0,1}[A-HJ])/g; for( @substrings ){ my $divisor = shift @divisors; my( $exponent, $letter ) = /(\d){0,1}([A-HJ])/; $exponent ||= 1; $result *= $p{ $letter } ** $exponent * $divisor; } return $result; } for( qw( 2A 2B 2A2B2C 4ABC 4AC ABC BC ) ){ print "string: $_\n"; my $result = calc( $_ ); print "result: $result\n\n"; }
    Output:
    string: 2A result: 1.125 string: 2B result: 3.125 string: 2A2B2C result: 28.423828125 string: 4ABC result: 7.308984375 string: 4AC result: 4.87265625 string: ABC result: 2.165625 string: BC result: 2.40625

    Same idea as everyone else, and also seems to give you some of your desired output (at least for the values of A, B, and C that you posted earlier - I believe your expected output above is using your earlier values, not 2.74, 2.65, and 2.5 as above).

    However, having said that - if this still doesn't satisfy your requirements, you really need to give us crystal clear requirements - because right now, we're working from a bare minimum. I'm sure you know what you mean, but we apparently do not. Start simple, like:

    Divisors: 50/100, 55/100, 60/100
    Values: A = 2, B = 3, C = 4.
    String: 2A
    Equation: ( A * A ) * ( 50 / 100 )
    Output: 2

    String: 3A
    Equation: ( A * A * A ) * 50 / 100
    Output: 4

    String: 2A2B
    Equation: ( ( A * A ) * ( 50 / 100 ) ) * ( ( B * B ) * ( 55 / 100 ) )
    Output: 9.9

    And then maybe introduce a few more advanced examples.



    --chargrill
    s**lil*; $*=join'',sort split q**; s;.*;grr; &&s+(.(.)).+$2$1+; $; = qq-$_-;s,.*,ahc,;$,.=chop for split q,,,reverse;print for($,,$;,$*,$/)
Re: regex and string functions help needed.
by monarch (Priest) on Oct 26, 2006 at 07:43 UTC
    valavanp,

    I think Corion has been very helpful to you.

    Perhaps the most important lesson about being a programmer is that a computer is dumb. It needs YOU, yes YOU to understand exactly how to work out an answer. A computer can calculate quicker than you but it is not smarter than you.

    It is clear that you did NOT understand your problem. If you did you'd have explained the solution clearly to others.

    Are you at university solving a homework problem? Are you employed in a company and have been given a task to solve? Be brutally honest about your motivations here. I believe Corion and others deserve that at least.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (7)
As of 2014-09-16 05:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite cookbook is:










    Results (157 votes), past polls