Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

Re: Converting words to numbers with HOP::Parser

by eric256 (Parson)
on Nov 06, 2005 at 05:08 UTC ( #506075=note: print w/replies, xml ) Need Help??

in reply to Converting words to numbers with HOP::Parser

I'm not sure if the post was just showing off HOP::Parser or what but I hacked together the following code just based on intuition. hehe. Tried to figure out exactly how i processed the numbers and make the computer do that.

use strict; use warnings; use Data::Dumper; use Test::More qw/no_plan/; my $nums_to_value = {}; my $i = 0; for (qw/zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eigh +tteen nineteen/) { $nums_to_value->{$_} = $i++; }; $i = 20; for (qw/twenty thirty forty fifty sixty seventy eighty ninety/) { $nums_to_value->{$_} = $i; $i += 10; } my $mag = { hundred => 100, thousand => 1_000, million => 1_000_000, billion => 1_000_000_000, }; #print Dumper($nums_to_value); sub num { my $word = shift; if (index( $word, '-') > 0) { my ($first,$second) = split /-/, $_; return undef unless exists $nums_to_value->{$first} and exists $nums_to_value->{$second}; return $nums_to_value->{$first} + $nums_to_value->{$second}; } else { return undef unless exists $nums_to_value->{$word}; return $nums_to_value->{$word}; } } sub word_to_decimal { my @words = @_; my $out; my $i = 0; for (@words) { my $temp = num($_); $i += length($temp); $out += $temp / 10**$i; } return $out; } sub word_to_num { my $text = shift; my @words = split / /, $text; my @que; my $scratch = 0; my $mod = 1; if ($words[0] eq 'negative') { $mod = -1; shift @words; } while (@words) { $_ = shift @words; my $temp = num($_); if (defined $temp) { $scratch += $temp; } elsif($_ eq 'and') { } elsif($_ eq 'point') { push @que, word_to_decimal(@words); @words = (); } else { my $magnitude = $mag->{$_}; my $sum = $scratch; while (@que && ($sum + $que[-1]) < $magnitude) { $sum += pop @que; } my $temp = ($sum || 1) * $magnitude; push @que, $temp; $scratch = 0; } } push @que, $scratch; my $out = sum(@que); return $mod * $out; } sub sum { my $temp = 0; $temp += $_ for @_; return $temp; } my $words = { 'three' => 3, 'forty' => 40, 'hundred' => 100, 'fourteen' => 14, 'thousand' => 1000, 'forty-two' => 42, 'ninety nine' => 99, 'hundred and two' => 102, 'hundred nineteen' => 119, 'hundred and twenty' => 120, 'hundred ninety-nine' => 199, 'two hundred and three' => 203, 'one thousand two hundred' => 1_200, 'one point one zero zero one' => 1.1001, 'negative hundred and three' => -103, 'twelve hundred and seventy three', => 1273, 'seven hundred thirty-three thousand' => 733_000, 'seven hundred thirty-three thousand five hundred', 733500, 'seven hundred thirty-three thousand five hundred and twenty-nine' +, 733529, 'seventy three point two four five' => 73.245, 'three point seventeen' => 3.17, 'seven million' => 7000000, 'two hundred and ninety six million four hundred and twenty-two th +ousand five hundred and seventy eight', 296_422_578, 'two hundred and ninety six million four hundred and twenty-two th +ousand five hundred and seventy eight point three four seven', 296422578.347, }; for my $word (sort {length $a <=> length $b} keys %$words) { my $num = $words->{$word}; is word_to_num($word), $num, "... $word should be $num"; }

It passes all your tests, but i'm not sure that means it will pass everything. Anyway just felt like hacking it together. ;)

Update: Turns out there IS a module for this. Still fun anyway and we have three completly different methods. Lingua::EN::Words2Nums

Eric Hodges $_='y==QAe=e?y==QG@>@?iy==QVq?f?=a@iG?=QQ=Q?9'; s/(.)/ord($1)-50/eigs;tr/6123457/- \/|\\\_\n/;print;

Replies are listed 'Best First'.
Re^2: Converting words to numbers with HOP::Parser
by Ovid (Cardinal) on Nov 06, 2005 at 19:55 UTC

    I missed that module when I was searching for it on the CPAN. Bummer.

    I find it interesting what extremely different styles our solutions have. Your's is quite procedural. Using a parser is declarative. What I find interesting about the latter is how one can pretty much rearrange all of the declarative portions of the parser and things still work as intended. This gives one a lot of flexibility.

    It's also (relatively) easy to extend. If I want to turn it into a calculator which responds appropriately to "divide three by seven and add twelve point two", I can do that. Further, it would merely build on what's there and nothing else would need to be touched. I wonder how feasible this is with a procedural model.

    In any event, your speculation was correct. My post was primarily intended to show off the power of the HOP::Parser as opposed to "hey, let's turn words into numbers!"


    New address of my CGI Course.

      Well with a quick regex you should be able to just grab out portions of text that it will be able to match to numbers. Then you could turn something like "divide three by seven and add twelve point two" into "divide 3 by 7 and 12.2", then you just have to manage the new portions. Frankly the parser version makes no sense at all to me and I have no idea what it is doing at all. A quick (realy quick) explanation might go along way for those of us who haven't read HOP, though I get more and more curious about HOP as these posts come out.

      Eric Hodges $_='y==QAe=e?y==QG@>@?iy==QVq?f?=a@iG?=QQ=Q?9'; s/(.)/ord($1)-50/eigs;tr/6123457/- \/|\\\_\n/;print;

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://506075]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (3)
As of 2020-11-24 17:59 GMT
Find Nodes?
    Voting Booth?

    No recent polls found