Tell me more ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

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'}

share|improve this question
Now that's a nice challenge. – FUZxxl Nov 14 '11 at 16:32
inverse stemming! interesting! I'll try to give a try when I get back home :) – DallaRosa Nov 15 '11 at 9:57
Any solution that's shorter than 1800 characters is incorrect (irregular verbs). – Quandary Nov 19 '11 at 8:00
@Quandary That's why I said '(Assume that the verb is regular)' – JiminP Nov 19 '11 at 10:55
@Quandary: Not quite true... see Belisarius' answer. – Simon Nov 26 '11 at 3:53
show 1 more comment

8 Answers

up vote 4 down vote accepted

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/
share|improve this answer

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']
share|improve this answer

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"}
share|improve this answer
You don't think that a dictionary look-up is kinda cheating? :-) – Simon Nov 26 '11 at 3:53
2  
@Simon Definitively no. WordData is part of the language :) – belisarius Nov 26 '11 at 12:44

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.

share|improve this answer

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'.

share|improve this answer

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")
  ))}
share|improve this answer

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"
share|improve this answer
Use Ruby 1.9 lambda syntax f=->(x){...} to get shorter code. Also aeiouy IMHO should be a constant. – Łukasz Niemier Feb 26 '12 at 21:53

Poop - 72 characters

f[s]s^6pow>4<<last&8*(/"ed""id""eid"/|out|flush)+rep'y'1-2-3"aeiou"ord#s
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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