# Write a function that returns past tense of given verb

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

function f(x){return x.replace(/([^aeiouy])y$/,'$1i').replace(/([^aeiouy][aeiou])([^aeiouy])$/,'$1$2$2').replace(/e$/,'')+'ed'} • Now that's a nice challenge. Commented Nov 14, 2011 at 16:32 • inverse stemming! interesting! I'll try to give a try when I get back home :) Commented Nov 15, 2011 at 9:57 • Any solution that's shorter than 1800 characters is incorrect (irregular verbs). Commented Nov 19, 2011 at 8:00 • @Quandary That's why I said '(Assume that the verb is regular)' Commented Nov 19, 2011 at 10:55 • @Quandary: Not quite true... see Belisarius' answer. Commented Nov 26, 2011 at 3:53 ## 9 Answers 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/


## 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"}

• You don't think that a dictionary look-up is kinda cheating? :-) Commented Nov 26, 2011 at 3:53
• @Simon Definitively no. WordData is part of the language :) Commented Nov 26, 2011 at 12:44

## 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']


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. # 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'. ### 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")
))}


# 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"

• Use Ruby 1.9 lambda syntax f=->(x){...} to get shorter code. Also aeiouy IMHO should be a constant. Commented Feb 26, 2012 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


## 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']