Last active
December 28, 2015 20:39
-
-
Save hernan604/7558496 to your computer and use it in GitHub Desktop.
Given a book, and two words from that book, create a method to give the smallest number of words between those two words.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package SmallExcerptBetweenTwoWords; | |
| use strict; | |
| use warnings; | |
| use utf8; | |
| use DDP; | |
| use Moo; | |
| =head1 SYNOPSIS | |
| Given a book, and two words from that book, create a method to give the smallest number of words between those two words. Assume that the book is large (over 500 pages) and memory usage and performance is a concern. | |
| =head2 USAGE | |
| You can tell this program to use a file: | |
| $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| file => "some_text_file.txt , | |
| wanted_words => [ qw/blalblla sksks/ ] | |
| ); | |
| $small_excerpt->start(); | |
| or you can specify the text as text_input: | |
| $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| text_input => "On the beach there WAS a BiG crazy woman throwin sand on everyone" , | |
| wanted_words => [ qw/biG womAn/ ] | |
| ); | |
| $small_excerpt->start(); | |
| and you must tell which wanted_words you are looking for. you must pass 2 wanted words. | |
| The words must no have spaces on it, because then its not a word. | |
| =cut | |
| has [qw/wanted_words wanted_words_lc /] => ( | |
| is => 'rw', | |
| ); | |
| has [qw/best_result all_results/] => ( | |
| is => 'rw', | |
| default => sub { {} }, | |
| ); | |
| has [qw/ | |
| file | |
| text_input | |
| errors | |
| word_counter | |
| answer | |
| / ] => ( | |
| is => 'rw', | |
| ); | |
| sub validate { | |
| my ( $self ) = @_; | |
| $self->errors( [] ); | |
| #check the user passed file and its readable | |
| if ( $self->file ) { | |
| push( @{ $self->errors } , | |
| "File doesnt exists or i dont have permission" ) if | |
| ! -e $self->file | |
| || ! -r $self->file; | |
| } | |
| #check if user did not pass file and neither text_input | |
| if ( ! $self->file and ! $self->text_input ) { | |
| push( @{ $self->errors } , <<'ERROR_MSG' | |
| You must set file or text_input before calling start() method. ie: | |
| my $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| file => "text" , | |
| ... | |
| ); | |
| or | |
| my $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| text_input => "some text bla bla bla bla" , | |
| ... | |
| ); | |
| ERROR_MSG | |
| ); | |
| } | |
| if ( ! $self->wanted_words | |
| || ref $self->wanted_words ne ref [] | |
| || scalar @{ $self->wanted_words } != 2 ) { | |
| push( @{ $self->errors }, <<'ERROR_MSG' | |
| You must pass in exactly 2 words to look for ex: | |
| SmallExcerptBetweenTwoWords->new( | |
| wanted_words => [ qw/first_word second_word/ ] | |
| ... | |
| ); | |
| or if you prefer: | |
| SmallExcerptBetweenTwoWords->new( | |
| wanted_words => [ 'first_word' 'second_word' ] | |
| ... | |
| ); | |
| ERROR_MSG | |
| ); | |
| } | |
| if ( $self->wanted_words | |
| and ref $self->wanted_words eq ref [] | |
| and scalar @{ $self->wanted_words } == 2 | |
| and lc @{ $self->wanted_words }[0] eq lc @{ $self->wanted_words }[1] | |
| ) { | |
| push ( @{ $self->errors }, "You must use different words for param wanted_words " ); | |
| } | |
| return 0 if scalar @{ $self->errors } > 0; | |
| return 1; | |
| } | |
| before 'start' => sub { | |
| my ( $self ) = @_; | |
| FORCE_CLEANUP: { | |
| $self->all_results( {} ); | |
| $self->best_result( {} ); | |
| $self->wanted_words_lc( [] ); | |
| $self->word_counter(0); | |
| } | |
| map { push( @{ $self->wanted_words_lc }, lc $_ ) } @{ $self->wanted_words }; | |
| }; | |
| sub start { | |
| my ( $self ) = @_; | |
| return if ! $self->validate; | |
| if ( $self->file ) { | |
| open FILE, $self->file; | |
| READ_FILE : { | |
| my $text; | |
| my $leftover = ""; | |
| while ( read FILE, $text, 10 ) { | |
| $text = $leftover . $text ; | |
| while ( $text =~ m/((\S+)\s+)|(\S+)/g ) { | |
| $leftover = ( defined $3) ? "$3" : ""; | |
| $self->compute_word( lc $2 ) if defined $2; | |
| } | |
| } | |
| } | |
| } | |
| elsif ( $self->text_input ) { | |
| #if the user passed an input, read it | |
| while ( $self->text_input =~ m/(\S+)/ig ) { | |
| $self->compute_word( lc $1 ); | |
| } | |
| } | |
| $self->show_results(); | |
| } | |
| sub show_results { | |
| my ( $self ) = @_; | |
| print "\n\n"; | |
| if ( keys %{ $self->best_result } ) { | |
| warn "------------------------------------------------------------------"; | |
| warn "The smallest number of words between '". join( ' and ', @{$self->wanted_words}) ."' is:\n"; | |
| warn "ANSWER: ".$self->best_result->{ words_between } . " words between\n"; | |
| } else { | |
| warn "ANSWER: found zero results.\n"; | |
| } | |
| } | |
| sub compute_word { | |
| my ( $self, $word ) = @_; | |
| next unless defined $word; | |
| REMOVE_UNWANTED_CHARS: { | |
| $word =~ s/^(\W)//; | |
| $word =~ s/(\W)$//; | |
| } | |
| if ( $self->is_word_1( $word ) ) { | |
| $self->reset_word_counter() if $self->word_counter != 0; | |
| $self->word_counter( $self->word_counter + 1 ); | |
| } | |
| elsif ( $self->is_word_2( $word ) and $self->word_counter != 0 ) { | |
| $self->word_counter( $self->word_counter + 1 ); | |
| my $words_between = $self->word_counter - 2; | |
| SAVE_THE_BEST_RESULT : { | |
| $self->best_result = { | |
| words_between => $words_between, | |
| } if ! keys $self->best_result | |
| || $self->best_result->{ words_between } > $words_between; | |
| $self->answer( $self->best_result->{ words_between } ); | |
| } | |
| $self->reset_word_counter(); | |
| } | |
| elsif ( $self->word_counter != 0 ) { | |
| $self->word_counter( $self->word_counter + 1 ); | |
| } | |
| } | |
| sub reset_word_counter { | |
| my ( $self ) = @_; | |
| $self->word_counter(0); | |
| } | |
| sub is_word_1 { | |
| my ( $self, $word ) = @_; | |
| return 1 if @{ $self->wanted_words_lc }[0] eq $word; | |
| return 0; | |
| } | |
| sub is_word_2 { | |
| my ( $self, $word ) = @_; | |
| return 1 if @{ $self->wanted_words_lc }[1] eq $word; | |
| return 0; | |
| } | |
| 1; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| echo "save the files above inside the same dir and execute: " | |
| prove -I. tests.pl |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use Test::More; | |
| use utf8; | |
| use lib "./"; | |
| use SmallExcerptBetweenTwoWords; | |
| my $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| file => "text" , | |
| wanted_words => [ qw/grande palaVra/ ], | |
| ); | |
| $small_excerpt->start(); | |
| is_deeply( | |
| $small_excerpt->best_result , | |
| { | |
| words_between => 0 | |
| } | |
| ,"Found expected result" | |
| ); | |
| is( $small_excerpt->answer , 0, "found correct answer, there are 0 words at the best answer" ); | |
| WORDS_THAT_DONT_EXISTS: { | |
| $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| file => "text" , | |
| wanted_words => [ qw/blalblla sksks/ ] | |
| ); | |
| $small_excerpt->start(); | |
| isnt( $small_excerpt->answer , defined, "did not find any answer for the given words" ); | |
| } | |
| #use DDP;warn p $small_excerpt->best_result; | |
| LOWER_CASE_UPPERCASE:{ | |
| $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| text_input => "On the beach there WAS a BiG crazy woman throwin sand on everyone" , | |
| wanted_words => [ qw/biG womAn/ ] | |
| ); | |
| $small_excerpt->start(); | |
| is( $small_excerpt->answer , 1, "correct" ); | |
| } | |
| PASS_ONLY_ONE_WORD_AS_ARGUMENT_SHOULD_THROW_ERROR: { | |
| $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| text_input => "On the beach there WAS a BiG crazy woman throwin sand on everyone" , | |
| wanted_words => [ qw/biG/ ] | |
| ); | |
| $small_excerpt->start(); | |
| isnt( $small_excerpt->answer , defined, "user must pass 2 words" ); | |
| ok( scalar( @{ $small_excerpt->errors } ) >= 1, " There are errors" ); | |
| ok( grep( /You must pass in exactly 2 words to look for/ , @{ $small_excerpt->errors } ) , "error msg in place" ); | |
| } | |
| DONT_PASS_A_FILE: { | |
| $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| wanted_words => [ qw/biG data/ ] | |
| ); | |
| $small_excerpt->start(); | |
| isnt( $small_excerpt->answer , defined, "user did not pass a file, should fail" ); | |
| ok( scalar( @{ $small_excerpt->errors } ) >= 1, " There are errors" ); | |
| ok( grep( /You must set file or text_input before calling start/, @{ $small_excerpt->errors } ) , "error msg in place" ) | |
| } | |
| ALLOW_ME_TO_PASS_TEXT_INPUT:{ | |
| $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| text_input => "the sun \nis shinning the the moon is dark. if its dark we see moon, else we see sun." , | |
| wanted_words => [ qw/sun moon/ ] | |
| ); | |
| $small_excerpt->start(); | |
| is( $small_excerpt->answer , 4, "worked" ); | |
| } | |
| SOME_NEW_LINES_IN_INPUT:{ | |
| $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| text_input => <<TEXT, | |
| the sun | |
| is shinning the | |
| the moon is dark. if its dark we see moon, else we see sun. | |
| TEXT | |
| wanted_words => [ qw/sun moon/ ] | |
| ); | |
| $small_excerpt->start(); | |
| is( $small_excerpt->answer , 4, "worked" ); | |
| } | |
| DOUBLE_CHECK_NEWLINES_IN_INPUT:{ | |
| $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| text_input => <<TEXT, | |
| the sun | |
| is shinning the | |
| the moon is dark. if its dark we see moon, else we see sun. | |
| The sun rises and the moon sets | |
| TEXT | |
| wanted_words => [ qw/sun moon/ ] | |
| ); | |
| $small_excerpt->start(); | |
| is( $small_excerpt->answer , 3, "worked" ); | |
| } | |
| BIG_TEXT_WITH_WORD_IN_BEGINING_AND_END:{ | |
| $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| text_input => <<TEXT, | |
| Sun Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla dolor odio, mollis ut tristique quis, malesuada ut lorem. Quisque at rutrum nulla. Duis tempor at ligula pharetra congue. Aenean quis elementum arcu, vel consectetur mauris. Praesent pharetra nisi ut risus tempor tempor. Nunc mattis erat nunc, vel tempus velit sodales aliquam. Phasellus ultrices ullamcorper aliquam. | |
| Nulla scelerisque felis placerat odio pulvinar, eget egestas turpis lacinia. Nam id suscipit dolor. Suspendisse orci urna, tristique quis leo eget, suscipit auctor sem. Integer scelerisque consectetur velit, id pellentesque est rhoncus et. Integer at arcu lacus. Etiam auctor eros vitae elit malesuada placerat. Nulla turpis tortor, volutpat eget aliquet nec, faucibus vitae moon. | |
| TEXT | |
| wanted_words => [ qw/sun moon/ ] | |
| ); | |
| $small_excerpt->start(); | |
| is( $small_excerpt->answer , 108, "worked" ); | |
| } | |
| PASS_SAME_WORD:{ | |
| $small_excerpt = SmallExcerptBetweenTwoWords->new( | |
| text_input => <<TEXT, | |
| Sun Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla dolor odio, mollis ut tristique quis, malesuada ut lorem. Quisque at rutrum nulla. Duis tempor at ligula pharetra congue. Aenean quis elementum arcu, vel consectetur mauris. Praesent pharetra nisi ut risus tempor tempor. Nunc mattis erat nunc, vel tempus velit sodales aliquam. Phasellus ultrices ullamcorper aliquam. | |
| Nulla scelerisque felis placerat odio pulvinar, eget egestas turpis lacinia. Nam id suscipit dolor. Suspendisse orci urna, tristique quis leo eget, suscipit auctor sem. Integer scelerisque consectetur velit, id pellentesque est rhoncus et. Integer at arcu lacus. Etiam auctor eros vitae elit malesuada placerat. Nulla turpis tortor, volutpat eget aliquet nec, faucibus vitae moon. | |
| TEXT | |
| wanted_words => [ qw/sun sun/ ] | |
| ); | |
| $small_excerpt->start(); | |
| ok( grep( /You must use different words for param wanted_words/ , @{ $small_excerpt->errors } ), "user should not pass the same word twice" ); | |
| } | |
| done_testing(); | |
| 1; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| um grande texto pode | |
| incluir uma palavra pequena e grande mas um texto grande realmente não pode incluir uma palavra muito pequena. Será que pode incluir palavra grande ? eu não sei mas estas palavras grandes podem ser complicadas de encontrar pois uma palavra pode estar fora de ordem equanto outra palavra pode estar na ordem. Já o trecho que tem menos palavras entre grande | |
| palavra só pode ser este, que vai resultar em zero. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment