views:

1747

answers:

32

I learned a lot about various languages last time I did one of these, so I figured I'd submit another. Community Wiki of course...

All programming languages are acceptable. The goal is to create the program in a language with the least amount of characters. New lines and indenting should be left in for clarity, but not counted. Try to just have 1 submission per language. Edit the existing one if you can make it shorter.


Write a program which takes 2 command line arguments as defined below:

Arg1: a string to be "encoded"

EncodeMe
Arg2: a pipe separated list of comma separated characters representing an encoding map to apply to the first argument. Example:
e,f|M,N|c,d|n,m|E,F|o,p|d,e
The program shall apply the character mapping specified in arg 2 to the characters of arg1, and display the output (map e to f, M to N, etc). The program above would output:
FmdpefNf
(not FodpefNf as originally posted)

Additional Info:

  • If a character in arg 1 is missing from the mapping in arg 2, that particular character should merely be skipped.
  • Assume that no invalid input will ever be given (lack of separator, too many separators, etc), so no additional error checking or handling is needed
+4  A: 

Mine isn't a serious golf entry, but should be quite succinct all the same:

my %map = split /[,|]/, $ARGV[1];
print map {$map{$_} || $_} split //, $ARGV[0];
Chris Jester-Young
heh. I came up with just about exactly the same idea.
dland
+4  A: 

C#

235 chars

using System.Linq;
class A
{
    static void Main(string[] c)
    {
        System.Console.WriteLine(new string(c[0].Select(a=>c[1].Split('|').ToDictionary(b=>b[0],b=>b[2]).FirstOrDefault(d=>d.Key.Equals(a)).Value).ToArray()).Replace("\0", ""));
    }
}

Credit goes to GalacticCowboy for the ingenious handling of missing mappings

TheSoftwareJedi
Here one what is 16 chars lower System.Console.Write(new string(A[0].Select(a => A[1].Split('|').ToDictionary(b=>b[0],b=>b[2])[a]).ToArray()));
MichaelT
Here's one that's slightly longer but takes missing chars into account. Console.WriteLine(new string(c[0].Select(a => c[1].Split('|').ToDictionary(b => b[0], b => b[2]).FirstOrDefault(d => d.Key.Equals(a)).Value).ToArray()).Replace("\0", ""));
GalacticCowboy
235 chars too!! :) :)
OscarRyz
pssst - see this entry: http://stackoverflow.com/questions/372668/code-golf-how-do-i-write-the-shortest-character-mapping-program#373392 212 characters - great ideas.
plinth
+11  A: 
dland
Good stuff! I hear that in Perl 5.10 you can use "say" instead of "print", don't quote me on this though. :-D
Chris Jester-Young
@Chris, you are entirely correct. And that saves me two characters, thanks!
dland
`say` must be explicitly enabled with something like `use 5.010;` in a script or `-E` switch on command-line.
J.F. Sebastian
The stackoverflow quote highlighter fails to parse Perl: it thinks that split// starts a end-of-line comment. But, the only program that can parse Perl is perl.
Hudson
I have never seen it correctly highlight any non-trivial Perl code.
Brad Gilbert
+3  A: 

ruby (105 characters):

m = ARGV[1].split('|').map {|p| p.split /,/}
puts ARGV[0].split(//).map {|c| m.assoc(c)[1] rescue c}.join
singpolyma
+3  A: 

C, unobfuscated:

#include <stdio.h>

int main(int argc, char **argv)
{
  int map[256];
  int i;
  for(i = 0; i < 256; i++)
    map[i] = i;
  do
  {
    map[(unsigned)*argv[2]] = argv[2][2];
    argv[2] += 4;
  } while(argv[2][-1]);

  while(*argv[1])
  {
    putchar(map[*argv[1]++]);
  }

  return 0;
}

Obfuscated, 108 characters:

int m[256];main(int c,char**v){while(v[2][3])m[*v[2]]=v[2][2],v[2]+=4;while(c=*v[1]++)putchar(m[c]?m[c]:c);}

Both programs assumed well-formed input. In particular, they assume that the second argument has exactly 3 more than a multiple of 4 characters. The second program also assumes that there are no values above ASCII 127 (or that characters are unsigned by default).

Adam Rosenfield
+2  A: 

F#:

#light
[<EntryPoint>]
let Main [|s;enc|] =
    let map = enc.Split([|'|'|]) |> Array.map (fun s -> s.[0],s.[2]) |> dict
    s |> Seq.map (fun c -> match map.TryGetValue(c) with | false,_ -> c | true,x -> x)
    |> Seq.to_array |> (fun a -> new System.String(a)) |> printfn "%s"
    0
Brian
A: 
using System.Linq;
class Program{
static void Main(string[] A)
{
System.Console.Write(new string(A[0].Select(
c => A[1]
    .Split('|')
    .Select(p => p.Split(','))
    .ToDictionary(s => s[0][0], s => s[1][0])[c]).ToArray()));    
}}
MichaelT
doesn't handle missing mappings
TheSoftwareJedi
+6  A: 

Python, 77 \S

import sys
s, t = sys.argv[1:]
print(''.join(map(dict(zip(t[::4], t[2::4])).get, s)))

It is a slightly modified version of @recursive's solution. It is Python 3.0 compatible. This version doesn't handle absent mappings.


Python, 80 \S

import sys, string as S
s, t = sys.argv[1:]
print s.translate(S.maketrans(t[::4], t[2::4]))

Characters with no mappings are translated as is.


Python, 83 \S

import sys
s, t = sys.argv[1:]
print(''.join(dict(zip(t[::4], t[2::4])).get(c, '') for c in s))

It is @recursive's solution (modified a bit). It is Python 3.0 compatible.


Python 84, \S

import sys
s, p = sys.argv[1:]
f, t = p[::4], p[2::4]
print(''.join((c + t)[f.find(c) + 1] for c in s))

Characters with no mappings are translated as is. It is Python 3.0 compatible.


Python, 104 non-whitespace characters

import sys, re, string as S
s, t = sys.argv[1:]
t = re.sub("[|,]", "", t)
print s.translate(S.maketrans(t[::2], t[1::2]))


Python 163 chars

import sys, string
subs= [m.split(",") for m in sys.argv[2].split("|")]
t= string.maketrans( "".join([s[0] for s in subs]), "".join([s[1] for s in subs]) )
print sys.argv[1].translate( t )

Might be a better way with iterools.


Python, 105 non-whitespace characters.

import sys,re
a = sys.argv
s = re.sub("[|,]","",a[2])
f = s[::2]
t = s[1::2]
print ''.join((c + t)[f.find(c) + 1] for c in a[1])

Not too happy about the last line.

S.Lott
See my solution. 99 non-whitespace bytes, and py3k compatible. We are treating missing translation entries differently though. I interpret skip to mean "omit from output".
recursive
A: 

For VB.NET (and VB)

Module Module1

Sub Main(ByVal a() As String)

    Dim d = a(0)
    Dim e = a(1).Split("|")

    For Each x In e
        d = d.Replace(Left(x, 1), Right(x, 1))
    Next

    Console.Out.Writeline(d)

End Sub

End Module

Note, this has the side-effect of repeating the mapping after characters have been changed, so c becomes d, but then that d becomes e, which may not be the desired result.

Ken Pespisa
+1  A: 

Java

235 not counting identetion nor new lines.

import java.util.*;
class E{
    public static void main(String[]a){ 
        Map r = new HashMap();
        for(String s:a[1].split("\\|")) 
            r.put(s.charAt(0),s.charAt(2));
        for (char c:a[0].toCharArray()) 
            System.out.print(r.get(c)==null?"":r.get(c));
    }
}
OscarRyz
I just answered your question about using the "golf" tag rather than "code-golf". Since it was about 10 days after your comment, I figured you might notice it better if I commented here also. :-D
Chris Jester-Young
Indeed. I don't like it, but I don't see anyone complaining either. So be it!.. Cheers!
OscarRyz
+2  A: 

TCL take 1, 152 chars.

foreach l [split [lindex $argv 1] |] {foreach {v m} [split $l ,] {set a($v) $m}}
foreach c [split [lindex $argv 0] ""] {catch {puts -nonewline $a($c)}}

Damn -nonewline.

TCL take 2, 63 chars.

puts [string map [split [lindex $argv 1] ,|] [lindex $argv 0]]

It's basically cheating, but I discovered in my search that TCL seems to have this command that does exactly this, I just need to format the input right.

TCL take 3, no cheating 93 chars.

set a [lindex $argv 0]
foreach {k v} [split [lindex $argv 1] ,|] {regsub $k $a $v a}
puts $a
psycotica0
"Cheating" is encouraged in code golf. ;)
GalacticCowboy
+1  A: 

PHP (99 chars)

foreach(str_split($argv[1])as$c)
    echo preg_replace('!(.*'.preg_quote($c).',(.))?.*!','$2',$argv[2]);

Without ignoring missing characters I got it down to 85.

preg_match_all('/(.),(.)/',$argv[2],$m);
echo strtr($argv[1],join($m[1]),join($m[2]));
mcrumley
You don't need {} for the one echo statement inside foreach.
too much php
Good catch, Peter. It's a habit -- Code golf is not my typical programming style.
mcrumley
Extra bonus for managing to include boobs in the second try.
Manos Dilaverakis
+2  A: 

Python

I don't see how to edit the existing posts, but here's my python approach. It spends two bytes on parens for python 3 compatibility.

import sys
p,k=sys.argv[1:]
print("".join(dict((v[0],v[2])for v in k.split("|")).get(c,"")for c in p))

It's 102 bytes including newlines. 93 non-whitespace.

recursive
You need 750 of rep to edit wiki posts. 2000 to edit others posts.
OscarRyz
I've added your solution to the main answer.
J.F. Sebastian
+1  A: 

JScript:

g=WScript.Arguments;
a=g(1).split("|");
r="";
for(i=0;i<g(0).length;i++)
    for(j=0;j<a.length;j++) {
     c=a[j].split(",");
     if(g(0).substr(i, 1)==c[0])
      r+=c[1];
    }
WScript.Echo(r);
RedFilter
+3  A: 

Groovy 52B

({s,m->s.any{x=m=~/$it,./;print x?x[0][-1]:it}})args

This is assuming that the map doesn't contain special chars for regex.

50B for 1.6rc1

(s,m)=args;s.any{x=m=~/$it,./;print x?x[0][-1]:it}
matyr
+1  A: 

C#

209 Characters

using System;using System.Linq;class P{static void Main(string[]a){var t=a[1].Split(',','|');Console.Write(a[0].Select(d=>{int i=Array.IndexOf(t,d.ToString());return i<0||i%1==1?'\a':t[i + 1][0];}).ToArray());}}

Readable version:

using System;
using System.Linq;
class P{
    static void Main(string[]a)
    {
        var t=a[1].Split(',','|');
        Console.Write(a[0].Select(d=> {
                 int i = Array.IndexOf(t,d.ToString());
                 return i < 0 || i % 1 == 1 ? '\a' : t[i + 1][0];
             }).ToArray());
    }
}

Edit: Shed another 3 chars - by the by, this takes advantage of the fact that '\0' has no output... Edit Edit: Gah - '\0' is a diamond in the console - my bad. Changed it to \a which is at least non-visual. '\0' is allegedly non-displaying. Edit Edit Edit: Added whitespace friendly version

plinth
No need for one line. Indentation and break lines are not counted.Plus we can't admire it like this :P
OscarRyz
+1  A: 

Javascript

I hope you don't mind this example in javascript, compatible with firefox, chrome and opera but not IE because of the way it accesses the elements of a string.

//102 characters if all non-essential whitespace is removed

function e( m, c ){
  var o = "", i = 0, j = 0,x = {};
  while( x[ c[i] ] = c[ ( i += 4 ) - 2 ] );
  while( i = m[ j++ ] ) o += x[ i ] || "";
  return o;
}

Can be tested with this:

alert(e('EncodeMe','e,f|M,N|c,d|n,m|E,F|o,p|d,e'));
some
+1  A: 

JavaScript

70 essential characters:

function e(s, m) {
    return (s + "|" + m).replace(/\|.*|(.)(?=.*\|\1,(.))/g, "$2")
}

This doesn't allow "|" in the target string.


74 characters. Compact form:

function e(s,m){return m.split(s[0]+",")[1][0]+(s[1]?e(s.substr(1),m):"")}

Readable form:

function e(s, m) {
    return m.split(s[0] + ",")[1][0] + (s[1] ? e(s.substr(1), m) : "");
}

e("EncodeMe", "e,f|M,N|c,d|n,m|E,F|o,p|d,e");

I have a hunch that I can trim a few more characters. Hmmm...

Ates Goral
@Ates Goral: It breaks if the input has a character that is not in the encoded part. But nice with recursion and the use of split!
some
@MizardX: Wow, just wow. I was trying to come up with a regex solution myself, but didn't think about this...
Ates Goral
@MizardX: Insane!! Wow!
some
+2  A: 

PHP: 83 characters

foreach(explode('|',$argv[2])as$s){$a.=$s[0];$b.=$s[2];}echo strtr($argv[1],$a,$b);

Disclaimer: Normally I don't endorse code which generates notices.

too much php
+4  A: 

Lua, 78 characters

None of the whitespace is necessary and so is not counted:

t={}
arg[2]:gsub('(%S),(%S)', function(l, r) t[l] = r end)
print((arg[1]:gsub('.', t)))

Explanation:

  1. t is a table implementing the character-character mapping specified by second argument.
  2. First gsub captures pairs of characters separated by commads and stores assocation in the table t. Function syntax is prolix.
  3. Second gsub replaces each char with its corresponding element in table t

Unpleasant sources of extra characters:

  • Anonymous function required big keywords function and end
  • Extra parens needed around gsub because it normally returns 2 values

Pleasant surprises: - gsub works well with functions and tables.

Norman Ramsey
Cool, dont see nearly enough of lua around here. +1!
RCIX
+2  A: 

My first Erlang attempt, ~400 chars

-module (encoder).
-export ([encode/2]).
-import (lists, [foldl/3, foldr/3]).
-import (string, [tokens/2]).
-import (proplists, [lookup/2]).

%%
%% encode the Src string with the given mapping string
%%
encode(Src,MapStr) ->
 Map = foldl(
 fun(X,Acc) ->
  [[K],[V]] = tokens(X,","),
  [{K,V}|Acc]
 end,
 [],
 tokens(MapStr,"|")
 ),
 foldr(
 fun(X,Acc) -> 
  [
  case lookup(X,Map) of
   {X,O} -> O; % X found, return mapping
   _  -> X % X not found, return X
  end
  |Acc] 
 end,
 [], 
 Src).


No need to do any advanced tokenizing, just write a lookup function which traverses the string. ~148 chars.

-module(i).
-compile(export_all).
l(K,[$||X])->l(K,X);
l(K,[K,$,,V|_])->V;
l(K,[_,$,,_|X])->l(K,X).
e(S,M)->lists:map(fun(X)->l(X,M)end,S).


Even shorter with list comprehensions (I just didn't thought about them yesterday :) ) ~120 chars:

-module(enc).
-export([enc/2]).
enc(S,M) ->
  [case proplists:lookup(C,[{K,V}||[K,$,,V]<-string:tokens(M,"|")])of{C,O}->O;_->C end||C<-S].
cheng81
+1  A: 

Ruby, 75 chars:

puts $*[0].gsub(/./){|c|eval("{'"+$*[1].gsub(/,|\|/,"','")+"'}").fetch c,c}

It first manipulates the second argument to Ruby's hash syntax, and then evals it and applies the hash to all chars.

Jules
+1  A: 

Euphoria

object
    e = command_line(),
    s = e[3]

e = 0 & 0 & e[4]

for i = 1 to length(s) do
    puts( 1, e[ match( s[i] & 44, e ) + 2] )
end for

94 non-whitespace characters.

Matt Lewis
+2  A: 

Ruby (62 char):

$*[0].split("").map{|c|$*[1][/#{c},./][2..-1] rescue c}.join
+2  A: 

Clojure (242 characters).

Could be better. I'm still very much a newbie in Clojure.

(defn enc [s e]
  (let [em (reduce #(conj %1 %2) (map #(hash-map (first %) (second %)) (partition 2 (re-seq #"\w" e))))]
    (apply str (map #(if (contains? em (str %))
                       (em (str %))
                       (str %)) s))))

I'm also cheating because I'm not technically taking command line arguments. This would be eval'd at a REPL.

user=> (enc "EncodeMe" "e,f|M,N|c,d|n,m|E,F|o,p|d,e")
"FmdpefNf"

Note: This might be a little easier to read here.


Take 2 (98 Characters)

A more concise solution with help from Chouser at #clojure at freenode.

(defn enc [s e] (apply str (map #(or ((into{} (for [[o _ n] (partition 3 4 e)] [o n])) %) %) s)))


Take 3 (78 Characters)

Mark Engelberg suggested this on the Clojure google group.

(defn enc [s e](apply str(map #(or ((apply hash-map(take-nth 2 e)) %) %)s)))
rzezeski
+1  A: 

C# without Linq 222 Bytes (including 5 newlines)

using System.Collections;class P{
static void Main(string[]a){
Hashtable ht=new Hashtable();
foreach(string t in a[1].Split('|'))ht.Add(t[0],t[2]);
foreach(char c in a[0])if(ht[c]!=null)System.Console.Write(ht[c]);
}}
devio
+2  A: 

I wrote the version of tr at http://asm.sourceforge.net/asmutils.html. The executable binary (no dependencies except for kernel) is 598 bytes.

EDIT: domain moved.

Joshua
Hacked account? Spam? this is weird. Why are you not just putting the code in the answer, this domain doesn't exist and is "for sale", so I conclude this is spam...
Petriborg
Neither. The domain was live when I posted it.
Joshua
+1  A: 
ja
+1  A: 

Scala (172 characters):

val m=scala.collection.mutable.Map.empty[Char,String]
args(1).split('|').map(_.split(',')).foreach((s)=>m+=s(0)(0)->s(1))
println(args(0).map((s)=>m.getOrElse(s,s)).mkString)
+1  A: 

If you change the format of the input slightly, this is a direct use of the tr program:

echo EncodeMe | tr eMcnEod fNdmFpe
Hudson
A: 

(Scala 177 characters)

class EncodeMe {
    def main(args:Array[String]) {
      var d = args(1).split('|').foldLeft(Map[Char, Char]()){(r, c) => r(c(0))=c(2)}
      println(args(0).foldLeft(""){ _+d(_)})
    }
}
Coral
A: 

C# 129 characters

class m{
    static void Main(string[] a){
        foreach (char c in a[0]){
            int d = a[1].IndexOf(c + ",");
            if (d >= 0) System.Console.Write(a[1][d + 2]);
        }
    }
}
Marcus Andrén