http://qs1969.pair.com?node_id=706786

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

Hello,

I'm looking for a module recommendation for the task of a spelling out a list as if it were an English phrase. It would compute the following, given phases of "a", "b" and "c:

a -> "a" a,b -> "a and b" a,b,c -> "a, b, and c" a,b,c,d -> "a, b, c, and d"
..and so forth. It wouldn't be so hard to write such a function, but it seems likely to already exist. Thanks!

Replies are listed 'Best First'.
Re: Module for making english lists?
by ysth (Canon) on Aug 26, 2008 at 00:48 UTC
      Conjunction Junction, what's your function?
      Thanks to everyone for the suggestions. I think I'll go with Linqua::Conjunction since it is already packaged up with docs and tests, and has some other options like using "or" instead of "and".
Re: Module for making english lists?
by moritz (Cardinal) on Aug 25, 2008 at 21:27 UTC
    Now it's written:
    #!/usr/bin/perl use strict; use warnings; my @list = ( [qw(a)], [qw(a b)], [qw(a b c)], ); for (@list){ print join_english(@$_), $/; } sub join_english { return $_[0] if @_ < 2; my $last = pop @_; return join(', ', @_), ' and ' . $last; }

    I don't know if that's worth a module, if you think so, you could upload it to CPAN as Lingua::List::English or something. I searched for lingua list and found nothing, but maybe I overlooked something.

Re: Module for making english lists?
by kyle (Abbot) on Aug 25, 2008 at 21:26 UTC

    Yeah, pretty easy to write...

    sub mkenglish { die 'arg required' if ! @_; if ( 1 == scalar @_ ) { return @_; } elsif ( 2 == scalar @_ ) { return join ' and ', @_; } else { my $last = pop @_; my $list = join ', ', @_; return "$list, and $last"; } }

    You might also be interested in reading about the Serial comma.

Re: Module for making english lists?
by Your Mother (Archbishop) on Aug 25, 2008 at 22:04 UTC

    How about serial comma function? :) Short enough to reproduce here. I use it in my TT2 filters.

    sub serial { join(', ', @_[0..$#_-1]) . (@_>2 ? ',':'' ) . (@_>1 ? (' and ' . $_[-1]) : $_[-1]); }
Re: Module for making english lists?
by AnomalousMonk (Archbishop) on Aug 26, 2008 at 00:02 UTC
    FWIW:

    perl -wMstrict -le "sub standard_commas { return @_ == 0 ? '' : @_ == 1 ? qq($_[0]) : @_ == 2 ? qq($_[0] and $_[1]) : join ', ', shift, standard_commas(@_) } sub oxford_commas { return @_ <= 2 ? standard_commas(@_) : @_ == 3 ? qq($_[0], $_[1], and $_[2]) : join ', ', shift, oxford_commas(@_) } for (@ARGV) { my @words = split; print qq(\nfor words: @words); print 'standard commas: ', standard_commas(@words); print 'oxford commas: ', oxford_commas (@words); } " "" "a" "a b" "a b c" "a b c d" "a b c d e" "a c d e f" for words: standard commas: oxford commas: for words: a standard commas: a oxford commas: a for words: a b standard commas: a and b oxford commas: a and b for words: a b c standard commas: a, b and c oxford commas: a, b, and c for words: a b c d standard commas: a, b, c and d oxford commas: a, b, c, and d for words: a b c d e standard commas: a, b, c, d and e oxford commas: a, b, c, d, and e for words: a c d e f standard commas: a, c, d, e and f oxford commas: a, c, d, e, and f
      Or, shorter, sweeter and non-recursive (and kind of a restatement of Your Mother's contribution):

      perl -wMstrict -le "sub standard_commas { return @_ == 0 ? '' : @_ == 1 ? qq{$_[0]} : join q{, }, @_[0 .. $#_ - 2], qq{$_[-2] and $_[-1]} } sub oxford_commas { return @_ < 3 ? standard_commas(@_) : join q{, }, @_[0 .. $#_ - 1], qq{and $_[-1]} } for (@ARGV) { my @words = split; print qq(\nfor words: @words); print 'standard commas: ', standard_commas(@words); print ' oxford commas: ', oxford_commas(@words); } " "" "a" "a b" "a b c" "a b c d" "a b c d e" for words: standard commas: oxford commas: for words: a standard commas: a oxford commas: a for words: a b standard commas: a and b oxford commas: a and b for words: a b c standard commas: a, b and c oxford commas: a, b, and c for words: a b c d standard commas: a, b, c and d oxford commas: a, b, c, and d for words: a b c d e standard commas: a, b, c, d and e oxford commas: a, b, c, d, and e
        And, since I don't seem to be able to let this go, still shorter and sweeter:

        sub standard_commas { return join q{, }, @_ < 2 ? @_ : (@_[0 .. $#_ - 2], qq{$_[-2] and $_[-1]}) } sub oxford_commas { return join q{, }, @_ < 3 ? goto &standard_commas : (@_[0 .. $#_ - 1], qq{and $_[-1]}) }
        Tested. The output, which I won't inflict upon you again, is the same.
Re: Module for making english lists?
by didess (Sexton) on Aug 25, 2008 at 21:52 UTC
    Hello, don't you think this is enough:
    #!/usr/bin/perl $S = "a , b, c,d"; sub modif { my ($S) = @_; $S =~ s/(.*),/$1 and /; $S =~ s/\s*,\s*/, /g; return $S; } print "\$S=$S ==> ". modif($S) . "\n";
    in case of an array (or list), join it with commas before:
    @Arr = (1 , 2, 3,4); print "Array = ". modif(join(',',@Arr)) . "\n";
    I don't think is worth a module! Hope it helps !
Re: Module for making english lists?
by Fletch (Bishop) on Aug 26, 2008 at 00:25 UTC

    Probably not the module you're looking for, but then again you're not going to be able to turn any of the others in for your homework either . . .

    module Main where eng_commafy :: (Show a) => [a] -> String eng_commafy x | length x > 2 = foldl1 (commacat) init_as_show ++ ", a +nd " ++ last_show where commacat x y = x ++ ", " ++ y init_as_show = map (show) (init x) last_show = show (last x) eng_commafy x | length x == 2 = (show (head x)) ++ " and " ++ (show (l +ast x)) eng_commafy x | length x == 1 = show (head x) eng_commafy [] = "" main = do putStrLn (eng_commafy [1..10]) putStrLn (eng_commafy [1,2]) putStrLn (eng_commafy [1])

    (Yeah, my Haskell's terrible . . . :)

    Update: Actually looking at the OP's posting history this is probably not homework. But it's still trivial and probably not past the threshold of "should be stuck in a module" on its own.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Module for making english lists?
by johndageek (Hermit) on Aug 26, 2008 at 22:03 UTC
    I dunno, try this just for fun

    #!/usr/bin/perl @str = ("a,b,c,d,e", "a", "a,b", "a,b,c"); foreach $x (@str){ $x =~ s/\,(\w+)$/ and $1/; print "$x\n"; }

    Enjoy!
    Dageek