Compress and Decompress sentence using vowel based encryption cipher

4

1

The aim is to parse a sentence and compress/encrypt it according to the rules below and then decrypt it using the key:

  1. Remove all letters in a word before the first vowel is encountered. Example: pigeon becomes igeon.

  2. All characters except alphabets should be kept in the sentence including numerals, punctuations, etc. Example: 200-storey building becomes 200-orey uilding.

  3. Generate the shortest key array char[] = {a,b,x,<your data>} and write code to generate the original sentence using this key.

You need to write two functions: encrypt() and decrypt() which works for every sentence minimising the key-size.

Example 1:

Input: The most technologically efficient machine man has ever invented is the book. -Northrop Frye-

Output: e ost echnologically efficient achine an as ever invented is e ook. -orthrop e-

Example key: {T,m,t,m,h,b,N,F,14,2,5}

Example 2:

Input: "I need your clothes, your boots and your motorcycle. " - The T-800 in Terminator 2: Judgment Day

Output: "I eed our othes, our oots and our otorcycle. " - e -800 in erminator 2: udgment ay

Example key: {n,y,c,2,b,2,m,T,J,D,15}

Winning Criteria:

  1. Write function encrypt() with input from stdin or file which generates output sentence and a key on stdout or file or memory.

  2. Write function decrypt() with inputs the generated sentence and key from encrypt() and produces the original sentence.

  3. This is code-golf so cumulative size of the two functions should be minimum. In case of tie-breaker, the generated key-size should be minimum.

manav m-n

Posted 2014-08-04T06:34:46.997

Reputation: 143

Question was closed 2014-08-05T19:03:42.030

Is there any specific format for the key array? – es1024 – 2014-08-04T06:46:56.623

You can make key in any format of your choice, there is no rules for generating the key – manav m-n – 2014-08-04T06:57:05.873

1In your first example, how does the key restore the 'Fry' of 'Frye'? – trichoplax – 2014-08-04T11:59:01.373

@githubphagocyte the key format and decoding logic entirely depends on you. You can form key in whatever format suitable for accurate decryption. – manav m-n – 2014-08-04T12:15:13.013

missing 'h' in the first example? – edc65 – 2014-08-04T15:47:58.470

Define "vowel". Is y a vowel? How about ü? Or ij in Dutch texts? Or the Turkish dotless i? – Peter Taylor – 2014-08-05T16:46:37.513

Answers

1

Perl5 61 + 30 = 91 122 211

This is based on the same idea as Comperendinous' Haskell answer where the key is indeed the whole cleartext and I cannot see anywhere in the rules that prevent this so kudos to Comperendinous :)

sub encrypt{$k=$_=<>;s/(.*?)\b[^\W\daeiou]+/$1/gi;print$_.$k}
sub decrypt{$i=<>;$_=<>;print}

Perl5 - 91 + 31 = 122

Here the key is slightly larger, but it actually prrduces the cleartext from the chipertext with the key so I find this more kosher.

sub encrypt{$_=<>;$k="s/(.{$+[1]})/\$1$+/;$k"while s/(.*)\b([^\d\Waeiou]+)/$1/i;print$_.$k}
sub decrypt{$_=<>;eval<>;print}

Ungolfed (though I've changed it to take parameters instead of two lines of text):

sub encrypt {
  my ($str) = @_;
  my $key = '';
  while( $str =~ s/(.*)\b([^\d\Waeiou]+)/$1/i ){
    $key = "\$str=~s/(.{$+[1]})/\$1$2/;$key";
  }
  ($str, $key);
}

sub decrypt {
  my ($str, $key) = @_;
  eval $key;
  $str;
}

Perl5 - 114 + 75 + 22 (shared) = 211

sub encrypt{$_=<>;@k=m/\b$x/ig;push@_,$+[1] while s/(.*?)\b$x/$1/i;print$_.join'',(@_,@k)[map{$_,$_+@k}0..$#k],$/}
sub decrypt{$i=<>;$_=<>;%k=m/(\d+)$x/g;print map{$k{$%++}|(),$_}split//,$i}
$x='([^\d\W\daeiou]+)'

With both functions chipertext is always output/input first, then the key.

Examples:

Input: 
The most technologically efficient machine man has ever invented is the book. -Northrop Frye-

Output:
e ost echnologically efficient achine an as ever invented is e ook. -orthrop e-
0Th2m6t31m38m41h61th63b69N77Fry

Input:
"I need your clothes, your boots and your motorcycle. " - The T-800 in Terminator 2: Judgment Day

Output:
"I eed our othes, our oots and our otorcycle. " - e -800 in erminator 2: udgment ay
3n7y11cl18y22b31y35m50Th52T60T73J81D

Ungolfed code:

# credit: http://stackoverflow.com/a/71895/1565698
sub zip {
    my $pivot = @_ / 2; 
    return @_[ map { $_, $_ + $pivot } 0 .. $pivot-1 ];
}

my $consonants = '([^\d\W\daeiou]+)';

sub encrypt {
  my $str = <>;
  my @matches = $str =~ m/\b$consonants/ig;
  my @indexes = ();
  while( $str =~ s/(.*?)\b$consonants/$1/i ) {
    push @indexes, $+[1]; # @+ has the match positions starting at 1
  }
  my $key = join('', zip(@indexes, @matches));
  print "$str$key\n";
}

sub decrypt {
 my $str =<>;
 my $key =<>;
 my %map = ( $key =~ m/(\d+)$consonants/g );
 my $index = 0;
 my @result = map{ $map{$index++} || (), $_ } split //, $str;
 print join '', @result;
}

Sylwester

Posted 2014-08-04T06:34:46.997

Reputation: 3 678

Your output has deleted the numerals from the input viz. T-800 and Terminator 2 – manav m-n – 2014-08-05T06:27:00.280

@Manav fixed. All 3 versions work correctly with numbers :) – Sylwester – 2014-08-05T16:48:28.050

1

Perl (126+67=193 characters)

Key contains each character removed along with its offset.

Encrypt reads one line from STDIN

Decrypt reads two: first the ciphered string then the key

sub encrypt{$_=<>;s(.)(++$j,$q|=$&=~/[aeiou]/i,$q^=$&eq$",!$q&$&=~/[a-z]/i&&(push@d,($&,$j-1))||print$&)ge;print$/.join',',@d}
sub decrypt{$q=<>,$_=<>;s/(.),(\d+)/substr($q,$2,0)=$1/gie;print$q}

Examples:

(encrypting)
The most technologically efficient machine man has ever invented is the book. -Northrop Frye-
> e ost echnologically efficient achine an as ever invented is e ook. -orthrop e-
> T,0,h,1,m,4,t,9,m,35,m,43,h,47,t,68,h,69,b,72,N,79,F,88,r,89,y,90

"I need your clothes, your boots and your motorcycle. " - The T-800 in Terminator 2: Judgment Day
> "I eed our othes, our oots and our otorcycle. " - e -800 in erminator 2: Judgment ay
> n,3,y,8,c,13,l,14,y,22,b,27,y,37,m,42,T,58,h,59,T,62,T,71,D,94

(decrypting)
e ost echnologically efficient achine an as ever invented is e ook. -orthrop e-
T,0,h,1,m,4,t,9,m,35,m,43,h,47,t,68,h,69,b,72,N,79,F,88,r,89,y,90
> The most technologically efficient machine man has ever invented is the book. -Northrop Frye-

"I eed our othes, our oots and our otorcycle. " - e -800 in erminator 2: Judgment ay
n,3,y,8,c,13,l,14,y,22,b,27,y,37,m,42,T,58,h,59,T,62,T,71,D,94
> "I need your clothes, your boots and your motorcycle. " - The T-800 in Terminator 2: Judgment Day

Ungolfed with comments

sub encrypt{
    # get input
    $_=<>;
    # for each character
    s(.)(
        # increment j
        ++$j,
        # set q to 1 if vowel
        $q |= $&=~/[aeiou]/i,
        # set q to 0 if space
        $q ^= $& eq $",
        # if q==0 and is a letter (consonant, because q=1 if vowel)
        !$q & $&=~/[a-z]/i &&
            # push both the letter and the offset to @d
            (push @d,($&,$j-1))
        # otherwise print
        || print$&
    )ge;
    # print a newline, then @d
    print$/.join',',@d
}
sub decrypt{
    # read a line to $q, and another to $_
    $q=<>,$_=<>;
    # for each [character],[number] in key
    s/(.),(\d+)/
        # add character back into string
        substr($q,$2,0)=$1
    /gie;
    # print deciphered string
    print$q
}

es1024

Posted 2014-08-04T06:34:46.997

Reputation: 8 953

why have you hardcoded $_="s,4,t,5,b,11";. Can you make a generalized solution. – manav m-n – 2014-08-04T12:17:44.157

@Manav fixed. Forgot to remove that when posting. – es1024 – 2014-08-04T12:43:49.090

1

Haskell: 119 = 111 + 8

Since there's no restriction on the key, I'm going agile and not getting any more complex until someone has a shorter answer:

e t=(unwords.map((\(a,b)->filter(not.(`elem`['a'..'z']++['A'..'Z']))a++b).break(`elem`"aeiouAEIOU")).words$t,t)
d(c,k)=k

I can make this at least 6 characters shorter if I import isAlpha from Data.Char. It's part of the standard distribution, so is it allowed?

comperendinous

Posted 2014-08-04T06:34:46.997

Reputation: 466

How do I test this? – Sylwester – 2014-08-05T10:55:44.270

Install Haskell, use ghci for a console, paste in the functions (in GHCi you'll need to precede each with let, call as e "200-storey building" and d ("200-orey uilding", "200-storey building"), which is what e should give you. – comperendinous – 2014-08-05T13:15:39.967