List the Cases of Two Finnish Nouns Introduction

In this challenge, your task is to correctly list the cases of two Finnish nouns.
The twist is that you may use one of the listings as a guide to produce the other.

The Nouns

We use the following two declination tables as our data.
They list the cases of two nouns, one case per line in the same order as in the Wikipedia article linked above, in the form singular : plural where applicable.

Table 1: Cases of ovi ("door")

ovi : ovet
oven : ovien
oven : ovet
ovea : ovia
ovessa : ovissa
ovesta : ovista
oveen : oviin
ovella : ovilla
ovelta : ovilta
ovelle : oville
ovena : ovina
oveksi : oviksi
ovin
ovetta : ovitta
ovine


Table 2: Cases of jalka ("foot")

jalka : jalat
jalan : jalkojen
jalan : jalat
jalkaa : jalkoja
jalassa : jaloissa
jalasta : jaloista
jalkaan : jalkoihin
jalalla : jaloilla
jalalta : jaloilta
jalalle : jaloille
jalkana : jalkoina
jalaksi : jaloiksi
jaloin
jalatta : jaloitta
jalkoine


The Task

Your task is to write two programs f and g (possibly with different names) that take one string as input, give one string as output, and have the following property.
If Table 1 is given to f as input, it outputs Table 2, and if Table 2 is given to g, it outputs Table 1.
All other inputs result in undefined behavior.
The tables must appear exactly as above in both input and output.
You may optionally assume that there is a trailing newline, but then it must be used in both tables, and in both input and output.
There is no preceding newline.

Rules and Bonuses

You can write f and g as either functions or full programs, but they must be of the same type, and they must be completely separate (if you write a helper function for f, you must re-write it in g if you want to use it there).
The lowest total byte count wins, and standard loopholes are disallowed.

There is a bonus of -25 % for not using regular expressions.

Some Clarifications

It is perfectly fine to write a function/program f that ignores its input and always returns Table 2, and a function/program g that always returns Table 1.
It is only required that f(Table 1) == Table 2 and g(Table 2) == Table 1; the behavior of f and g on all other inputs is irrelevant.

The "completely separate" part means the following.
Your answer provides two pieces of code, one for f and one for g, preferably in different code boxes.
If I put the code for f in a file and run it, it works, and the same for g.
Your score is the sum of the byte counts of the two pieces of code.
Any duplicated code is counted twice.
Perl, 105 + 54 = 159

Program f (try me):

#!perl -p
s/vi /vka /;s/ve/va/g;s/en/an/;s/vi/voi/;s/ov/1&amp;34960&gt;&gt;$.?jalk:jal/eg;s/ii/ihi/;s/loia/lkoje/;s/oia/oja/


Program g (try me):

#!perl -p
s/jalk?o?/ov/g;s/va /vi /;s/va/ve/g;s/an/en/;y/jh/i/d


An alternative version of f, only 2 bytes longer (this method can be also applied to g but it would be too long):

#!perl -p0
ka1a1a1koj1a1a1ka1koj1a1o0a1o0kaa2koih1a1o0a1o0a1o0ka1ko0a1o0o0a1o0ko=~s!\D+!"s/ov".'.'x$'."/jal$&amp;/"!gree


Technically this still uses a regexp (to decode the substitution string and then to apply them) so I cannot claim the bonus here.