Write a function that returns past tense of given verb

14

1

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

JiminP

Posted 2011-11-14T02:44:36.470

Reputation: 3 264

something directly related to it, can there be a function which returns the third form? – Shaheer – 2012-02-23T19:57:33.520

Now that's a nice challenge. – FUZxxl – 2011-11-14T16:32:20.673

inverse stemming! interesting! I'll try to give a try when I get back home :) – DallaRosa – 2011-11-15T09:57:02.417

Any solution that's shorter than 1800 characters is incorrect (irregular verbs). – Quandary – 2011-11-19T08:00:46.947

@Quandary That's why I said '(Assume that the verb is regular)' – JiminP – 2011-11-19T10:55:36.737

@Quandary: Not quite true... see Belisarius' answer.

– Simon – 2011-11-26T03:53:36.030

Answers

6

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/

migimaru

Posted 2011-11-14T02:44:36.470

Reputation: 1 040

4

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

Dr. belisarius

Posted 2011-11-14T02:44:36.470

Reputation: 5 345

You don't think that a dictionary look-up is kinda cheating? :-) – Simon – 2011-11-26T03:53:05.593

3@Simon Definitively no. WordData is part of the language :) – Dr. belisarius – 2011-11-26T12:44:28.677

3

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

Armand

Posted 2011-11-14T02:44:36.470

Reputation: 499

2

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.

Prakash K

Posted 2011-11-14T02:44:36.470

Reputation: 121

2

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

han

Posted 2011-11-14T02:44:36.470

Reputation: 1 226

1

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

user unknown

Posted 2011-11-14T02:44:36.470

Reputation: 4 210

0

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

Coding man

Posted 2011-11-14T02:44:36.470

Reputation: 1 193

0

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"

LBg

Posted 2011-11-14T02:44:36.470

Reputation: 130

Use Ruby 1.9 lambda syntax f=->(x){...} to get shorter code. Also aeiouy IMHO should be a constant. – Hauleth – 2012-02-26T21:53:01.690

0

Poop - 72 characters

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

Thomas Eding

Posted 2011-11-14T02:44:36.470

Reputation: 796