MadhAric has asked for the wisdom of the Perl Monks concerning the following question:

I have a sentence. My task is to find out whether the articles A and An are properly used. if a followed by a vowel , replace it with an (like replace a apple with an apple) and vice versa replace an dog with a dog. can you please tell me the code I am with basic level of PERL and wrote the following piece which did not give the desired result $string =~ (s/a (a|e|i|o|u)/an /g); print "\n$string\n"; Do we need to use loops and sub strings for this

Replies are listed 'Best First'.
Re: Perl pattern matching question
by choroba (Cardinal) on May 06, 2015 at 09:05 UTC
    Use \b for word boundaries and character classes instead of alternatives of single characters:
    #!/usr/bin/perl use strict; use warnings; my @strings = ('A dog ate an apple', 'A apple ate a dog', 'A apple ate a oak', ); for my $string (@strings) { $string =~ s/\b([Aa])(\s+[aeiou])/$1n$2/g; print "$string\n"; }

    What would you use before the following words, though?

    heir user XML yak ylem

    You need pronunciation, not spelling. Update: check Text::Phonetic and related modules for that.

    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Update: Note failure in the case of 'an log'.

      c:\@Work\Perl\monks\MadhAric>perl -wMstrict -le "my $string = 'A log and a axe, an log and an axe'; print qq{'$string'}; ;; $string =~ s/\b([Aa])(\s+[aeiou])/$1n$2/g; print qq{'$string'}; " 'A log and a axe, an log and an axe' 'A log and an axe, an log and an axe'

      Even ignoring the subtleties of pronunciation you pointed out, the OPed problem statement is tricky. Some cases need 'n' deleted, so I don't see how it can be done (in a single regex) without decision-making in the replacement clause, i.e., use of the  /e modifier or equivalent trick.


      Give a man a fish:  <%-(-(-(-<

Re: Perl pattern matching question
by vinoth.ree (Monsignor) on May 06, 2015 at 08:58 UTC

    Read perlrequick, perlre,perlrecharclass

    1.Read how to match a string.
    2.Read How to group a matched string
    
    Ex,
    my $str="a apple"; $str =~(s/a(\s+[aeiou].+)/an\1/g); print $str

    All is well. I learn by answering your questions...

      sure vinoth, an alteration of single characters should be a character class :)

      and we're on our way with the help from Basic debugging checklist

      use Data::Dump qw/ dd /; my $string = 'and a one and a two and a panda is a animal'; $string =~ (s/a (a|e|i|o|u)/an /g); dd( $string ); __END__ "and an ne and a two and a pandan s an nimal"
Re: Perl pattern matching question
by graff (Chancellor) on May 07, 2015 at 03:08 UTC
    As with a surprising number of similar issues relating to human language, there's already a module on CPAN for this: Lingua::EN::Inflect -- behold:
    #!/usr/bin/env perl use strict; use warnings; use Lingua::EN::Inflect 'A'; while (<DATA>) { while ( /\b (an? \s (\w+))/gx ) { my ( $phrase, $word ) = ( $1, $2 ); if ( $phrase eq A( $word )) { print "RIGHT: $phrase\n"; } else { print "WRONG: $phrase\n"; } } } __DATA__ I am a howling maniac in an hospital. It takes a hour to win an honorable mention. Calling him a umpire is a euphemism. This is a united front against a evil empire.
    That just shows how to use the module to check for errors. It should be easy to tweak the example a bit so as to fix them.

    (updated to fix a typo in the cpan link.)

    One more update: a bit more logic is needed to handle various kinds and amounts of punctuation that might occur between the article and the word that follows:

    while (<DATA>) { while ( /\b ((an?) \s\W* (\w+))/gx ) { my ( $phrase, $article, $word ) = ( $1, $2, $3 ); my $bigram = "$article $word"; if ( $bigram eq A( $word )) { print "RIGHT: $phrase\n"; } else { print "WRONG: $phrase\n"; } } } __DATA__ Suitable for a (older) child or an 'early adult'.
Re: Perl pattern matching question
by AnomalousMonk (Archbishop) on May 07, 2015 at 01:21 UTC

    Here are a couple of similar approaches that differ in using a regex feature introduced in Perl version 5.10. These regexes may be a bit beyond your current regex understanding; if so, this may serve as a spur. I think the main idea to take away is of building a unit testing framework in which different approaches (to what looks like your homework) can be tried. (The original file contains other variations, but I think the ones I've shown are the best.) See Test::More and friends.


    Give a man a fish:  <%-(-(-(-<