15
\$\begingroup\$

Challenge

Write a function which takes an argument which is a verb, and returns the past tense of the verb. (Assume that the verb is regular)

Past tense

Note: consider y as neither consonant nor vowel.

Normally, just adding ed after the end of verb makes the past tense of the verb.

Ex: jumpjumped, askasked

However, there are other rules.

  • If the last character of the given verb is e, just add d.

    Ex: loveloved, movemoved

  • If the verb is ended with a consonant + y, then change y to i, and add ed.

    Ex: studystudied, crycried

  • However, if the verb is ended with a vowel + y, then just add ed.

    Ex: playplayed, staystayed

  • If a verb is ended with a vowel and a consonant, then write the consonant one more time, and add ed.

    Ex: stopstopped, planplanned

  • However, if a verb is ended with multiple vowels + a consonant or single vowel + multiple consonants, then just add ed.

    Ex: looklooked, jumpjumped

There are more rules but let's care above rules only. For example, according to above rule, visitvisitted.

Winner

Since this is code golf, the shortest code that correctly returns past tenses wins.

Example (JS, 127)

function f(x){return x.replace(/([^aeiouy])y$/,'$1i').replace(/([^aeiouy][aeiou])([^aeiouy])$/,'$1$2$2').replace(/e$/,'')+'ed'}

\$\endgroup\$
6
  • \$\begingroup\$ Now that's a nice challenge. \$\endgroup\$
    – FUZxxl
    Commented Nov 14, 2011 at 16:32
  • \$\begingroup\$ inverse stemming! interesting! I'll try to give a try when I get back home :) \$\endgroup\$
    – DallaRosa
    Commented Nov 15, 2011 at 9:57
  • \$\begingroup\$ Any solution that's shorter than 1800 characters is incorrect (irregular verbs). \$\endgroup\$
    – Quandary
    Commented Nov 19, 2011 at 8:00
  • \$\begingroup\$ @Quandary That's why I said '(Assume that the verb is regular)' \$\endgroup\$
    – JiminP
    Commented Nov 19, 2011 at 10:55
  • \$\begingroup\$ @Quandary: Not quite true... see Belisarius' answer. \$\endgroup\$
    – Simon
    Commented Nov 26, 2011 at 3:53

9 Answers 9

7
\$\begingroup\$

sed, 76 characters

Does a sed script count as a function for this problem?

s/\([^aeiou]\)y$/\1i/
s/\([^aeiou][aeiou]\)\([^aeiouy]\)$/\1\2\2/
s/e\?$/ed/
\$\endgroup\$
5
\$\begingroup\$

Mathematica 43 chars

f=WordData[#,"InflectedForms","List"][[1]]&

Usage:

f /@ {"call", "try", "use", "wash", "play", "stop", "look"}

{"called", "tried", "used", "washed", "played", "stopped", "looked"}

Also:

f /@ {"buy", "run", "swim"}

{"bought", "ran", "swam"}
\$\endgroup\$
2
  • \$\begingroup\$ You don't think that a dictionary look-up is kinda cheating? :-) \$\endgroup\$
    – Simon
    Commented Nov 26, 2011 at 3:53
  • 3
    \$\begingroup\$ @Simon Definitively no. WordData is part of the language :) \$\endgroup\$ Commented Nov 26, 2011 at 12:44
3
\$\begingroup\$

Groovy - 111 characters

v={it==~'[aeiou]'};p={s->r=s[0..-2];a=s[-1];b=v s[-2];(a=='e'?r:a=='y'?!b?r+'i':s:v(s[-3])|!b|v(a)?s:s+a)+'ed'}

assert ['jump', 'ask', 'love', 'move', 'study', 'cry', 'play', 'stay', 'stop', 'plan', 'look'].collect { p(it) } == ['jumped', 'asked', 'loved', 'moved', 'studied', 'cried', 'played', 'stayed', 'stopped', 'planned', 'looked']
\$\endgroup\$
2
\$\begingroup\$

Perl 5 (82 characters):

sub f{$_=pop;$C='[^aeiouy]';s/($C)y$/$1i/;s/($C[aeiou])($C)$/$1$2$2/;s/e?$/ed/;$_}

I am sure it can be improved.

\$\endgroup\$
2
\$\begingroup\$

C - 120 119 characters

In typical C style, the function f updates a string buffer in place, assuming that the caller has reserved enough space for up to three extra characters. The second argument should be given as 0. The declaration of the global state variable l is included in the total character count.

#include <stdio.h>
#include <string.h>

l;void f(b,i)char*b;{*b?f(b+1,i/2+4*!strchr("aeiouy",l=*b)):(i-5?*--b=l=='y'&i/2?'i':l:(*b=l),strcpy(b+=l!='e',"ed"));}

int main()
{
  char b[10000];
  while (gets(b)) {
    f(b,0);
    puts(b);
  }
  return 0;
}

Explanation: The function iterates over the characters recursively. The second argument i encodes which of the previous three characters were consonants in its bottom three bits. At the end of the string, if i==5 then the last three characters were a consonant, a vowel and a consonant, and thus the last character must be duplicated. Similarly, if bit 1 of i indicates that the second-to-last character was a consonant and the last character is 'y', then the 'y' is replaced by 'i'.

\$\endgroup\$
1
\$\begingroup\$

Scala 199 273 chars

def v(c:Char)="aeiouy" contains c
def p(o:String)={val s=o.reverse
if(s(0)=='e')o+"d"else
if(!v(s(1))&& s(0)=='y')o.replaceAll("y$","ied")else
if(!v(s(0))&& v(s(1))&& !v(s(2)))o+s(0)+"ed"else
o+"ed"}

Invocation:

val li = List ("move", "cry", "plan", "play", "look")
li map p

My first approach was much longer, by moving the if-else-cascade to a list=> to a function:

type S=String
def f(l:List[(Boolean,S)]):S=if(l(0)._1)l(0)._2 else f(l.tail)
def v(c:Char)="aeiouy" contains c
def c(o:S)={val s=o.reverse
f(List((s(0)=='e',o+"d"),(!v(s(1))&& s(0)=='y',o.replaceAll("y$","ied")),(!v(s(0))&& v(s(1))&& !v(s(2)),o+s(0)+"ed"),(true,o+"ed")))}

Maybe the approach is interesting. Degolfed and explained:

// just for shortening
type S=String
/* take a list of Booleans and Strings, and return early
   if a Boolean is true. This approach would work, 
   if there where much more conditions, I guess.
*/
def doFirst (list: List[(Boolean, S)]): S =
  if (list(0)._1) list(0)._2 else doFirst (list.tail)
// vocal - is it a vocal
def v(c:Char)="aeiouy" contains c
// here is the key function
def toPast(o:S)={
  // reversing the String allows easy access to the last elements, 
  // without considering how long the string is.
  val s=o.reverse
  doFirst (List (
    (s(0)=='e', o+"d"),
    (!v(s(1)) && s(0)=='y', o.replaceAll("y$","ied")),
    (!v(s(0)) && v(s(1)) && !v(s(2)), o+s(0)+"ed"),
    (true, o+"ed")
  ))}
\$\endgroup\$
0
\$\begingroup\$

Ruby, 101 characters

Probably can be smaller.

def f x;x.sub(/([^aeiouy])y$/,'\1i').sub(/([^aeiouy][aeiou])([^aeiouy])$/,'\1\2\2').sub(/e$/,'')+'ed';end

Usage:

f("try")  #=> "tried"
f"call"   #=> "called"
\$\endgroup\$
1
  • \$\begingroup\$ Use Ruby 1.9 lambda syntax f=->(x){...} to get shorter code. Also aeiouy IMHO should be a constant. \$\endgroup\$
    – Hauleth
    Commented Feb 26, 2012 at 21:53
0
\$\begingroup\$

Poop - 72 characters

f[s]s^6pow>4<<last&8*(/"ed""id""eid"/|out|flush)+rep'y'1-2-3"aeiou"ord#s
\$\endgroup\$
0
\$\begingroup\$

Python - 147

def f(v):T,x,m='aeiou',"ed",v[-1];return[[[v+x,v+m+x][v[-2]in T and m and v[-3]not in T],[v+x,v[:-1]+"ied"][v[-2]not in T]][m=='y'],v+"d"][m=='e']  
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.