Replace letters by their rank, keeping punctuation intact

The problem is simple. Given a string such as "Hello World" the program would output "8-5-12-12-15 23-15-18-12-4-!". Any delimiters will do, (please specify what they are though) I just chose to use space between words and dashes between characters.

The conversion is that all alphabetical characters will be converted to their numeric equivalent. i.e. A=1,B=2,...,Z=26. All other characters must be kept intact. Case insensitive. Another example

Here's another example, I hope that this will illustrate my point! If it's unable, more specs will be given.
8-5-18-5-'-19 1-14-15-20-8-5-18 5-24-1-13-16-12-5-, 9 8-15-16-5 20-8-1-20 20-8-9-19 23-9-12-12 9-12-12-21-19-20-18-1-20-5 13-25 16-15-9-14-20-! 9-6 9-20-'-19 21-14-1-2-12-5-, 13-15-18-5 19-16-5-3-19 23-9-12-12 2-5 7-9-22-5-14-.


Note that there are no trailing or starting delimiters between characters.

Scoring will be based on the shortest amount of code. Any language is welcome.

As long as more answers are provided I will change the winner. GLHF!

• One test case does not constitute a specification. – Peter Taylor Aug 7 '13 at 17:03
• @JanDvorak that would be acceptable as well. Just indicate which delimiters are being used. – Taka Aug 7 '13 at 17:12
• What is an "alphabetical character"? Just A-Za-z with no accents? And is this really cryptography? – Peter Taylor Aug 7 '13 at 17:13
• @PeterTaylor alphabetical character is A-Za-z, case insensitive. It's a basic cypher. – Taka Aug 7 '13 at 17:16
• @Taka it's not an encryption. It's an encoding. Lossy encoding, and inefficient. – John Dvorak Aug 7 '13 at 17:17

GolfScript (24 22 chars)

{.32|96^:@]@(26/!=n}%


is a hybrid of Howard's solution and my previous one:

{.223&65-.26/!{)\}*;n}%


Since the spec states that I can use any delimiter, I've chosen to use newline.

Online demo

• Nice abuse of the delimiter rule! – user8777 Aug 8 '13 at 3:28
• I'd like to upvote your solution - but you don't have a word delimiter, do you? – Howard Aug 8 '13 at 4:05
• @Howard, I don't have a different word delimiter, but the spec is so vague that it doesn't seem to require one. – Peter Taylor Aug 8 '13 at 6:53
• @PeterTaylor It does. Take e.g. "Hello\nworld" as input and you'll end up with three delimiters between words instead of one. (btw. my solution reduces to 23 chars if I'd take the same approach ;-) ) – Howard Aug 8 '13 at 11:23
• @Howard if you put a delimiter in the input to any of the programs it would look like it was more. Unless we want to clear for those, which isn't specified. This keeps it intact, technically. – Taka Aug 8 '13 at 13:55

Ruby 2.0, 41+1 characters

There, now it complies with the updated rules and makes prettier output.

gsub(/\w+/){$&.chars.map{|c|c.ord&31}*?-}  Run with -p switch: ruby -p ord.rb <<< "ABC! Defghi, jklmnopqr stuvwxyz" 1-2-3! 4-5-6-7-8-9, 10-11-12-13-14-15-16-17-18 19-20-21-22-23-24-25-26  • Nice one. But seems there should be no dashes around the spaces. – manatwork Aug 7 '13 at 17:35 • Nice answer. I think you can do c.ord&31 and save 5 characters ;) – epidemian Aug 8 '13 at 1:20 • Even greater. But still a glitch: now there are no separators neither around the unencoded characters. – manatwork Aug 8 '13 at 7:44 • @daniero, I somehow agree. (You got my upvote anyway.) I was just curious whether more spectacular twists can be condensed in that code. (My first unposted try was also in ruby. About double of your code…) – manatwork Aug 9 '13 at 15:54 • @manatwork Thank you. Yes, I think separating and dealing with the non-alpha characters more precisely takes way more code. In codegolf I prefer shorter code and less accurate output; Dealing with special cases is not the golfing way. I first tried some more complicated stuff, but this bug and some other weird behavior made me call it off. – daniero Aug 9 '13 at 17:28 Perl: 42 38 characters s/\S(?=\S)/$&-/g;s/[a-z]/31&ord$&/ige  Sample run: bash-4.1$ perl -pe 's/\S(?=\S)/$&-/g;s/[a-z]/31&ord$&/ige' <<< "Here's another example, I hope that this will illustrate my point! If it's unable, more specs will be given."
8-5-18-5-'-19 1-14-15-20-8-5-18 5-24-1-13-16-12-5-, 9 8-15-16-5 20-8-1-20 20-8-9-19 23-9-12-12 9-12-12-21-19-20-18-1-20-5 13-25 16-15-9-14-20-! 9-6 9-20-'-19 21-14-1-2-12-5-, 13-15-18-5 19-16-5-3-19 23-9-12-12 2-5 7-9-22-5-14-.

• You can shorten the replacement part of the second substitution to 31&ord$&. – Gilles Aug 7 '13 at 21:43 • In the second substitution, [a-z] may be replaced by \pL, making the i flag unnecessary. – primo Aug 8 '13 at 9:35 • Thank you, @primo. Unicode character properties somehow didn't made their way into my regular expressions. As “alphabetical character is A-Za-z”, this will somehow violate the rules. But will keep it in mind and use it if the other answers will have more relaxed attitude on respecting the rules. – manatwork Aug 8 '13 at 9:57 GolfScript, 3736 23 characters The following version takes newline as delimiter (as Peter's solution): {.32|96^:@]@27,?0>=n}%  A version which interprets words and delimiters as in the examples given is 36 characters long: ' '/{'-'*{.32|96^:@]@27,?0>=}%' '}%  (Strange enough my first version '-''- -'/' '{.32|96^:@@0>@27<&if}% didn't work...) Takes input on STDIN. The example can be tested online: > 'Hello world!' 8-5-12-12-15 23-15-18-12-4-!  • Could you show how to run it. Using golf online – Taka Aug 7 '13 at 22:16 R - 134 characters A bit too long to be really in competition but here we go: s=sapply l=letters cat(s(strsplit(scan(,""),""),function(x)paste(s(tolower(x),function(y)ifelse(y%in%l,which(l==y),y)),collapse="-")))  Word delimiter is space, character delimiter is -. Tcl, 82 lmap a [split [string tol$i] {}] {expr {[string is alpha $a]?[scan$a %c]-96:$a}}  Because you did not specify what you want, well, here an expression. Input in i, result of the expression is the result. Example: % set i "Hello World!" Hello World! % lmap a [split [string tol$i] {}] {expr {[string is alpha $a]?[scan$a %c]-96:$a}} 8 5 12 12 15 { } 23 15 18 12 4 !  Word delimiter is { }, character delimiter is Python - 47 63 This assumes you've assigned the string to the variable s. 47 uses a flagrant abuse of the rules and says that [ is the delimiter for the start of the original string, ] marks the end of the original string, , marks the different characters and unchanged characters are captured in quotes. str([(x,ord(x)-64)[x.isalpha()] for x in s.upper()])  Alternatively, 62 squeezes a line from below (although 'A'<=x<='Z' is just as long and works just as well.: '-'.join([str((x,ord(x)-64)[x.isalpha()]) for x in s.upper()])  63: '-'.join([str((x,ord(x)-64)[64<ord(x)<91]) for x in s.upper()])  And the sample output: >>> s = "Hello World!" >>> '-'.join([str((x,ord(x)-64)[64<ord(x)<91]) for x in s.upper()]) '8-5-12-12-15- -23-15-18-12-4-!'  • I'm not sure I would consider these programs, as they don't read any input from stdin, nor do they write any output to stdout. A 52 byte program, abusing the newline delimeter as @PeterTaylor does: for x in raw_input():print(x,ord(x)&31)[x.isalpha()] – primo Aug 8 '13 at 10:46 Mathematica 68 Commas used as separators. If[64 < # < 97, # - 64, FromCharacterCode@#] & /@ ToCharacterCode@ToUpperCase@i  Example i="To be, or not to be,--that is the question:-- Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them?"; If[64 < # < 97, # - 64, FromCharacterCode@#] & /@ ToCharacterCode@ToUpperCase@i  {20, 15, " ", 2, 5, ",", " ", 15, 18, " ", 14, 15, 20, " ", 20, 15, " ", 2, 5, ",", "-", "-", 20, 8, 1, 20, " ", 9, 19, " ", 20, 8, 5, " ", 17, 21, 5, 19, 20, 9, 15, 14, ":", "-", "-", " ", 23, 8, 5, 20, 8, 5, 18, " ", "'", 20, 9, 19, " ", 14, 15, 2, 12, 5, 18, " ", 9, 14, " ", 20, 8, 5, " ", 13, 9, 14, 4, " ", 20, 15, " ", 19, 21, 6, 6, 5, 18, " ", 20, 8, 5, " ", 19, 12, 9, 14, 7, 19, " ", 1, 14, 4, " ", 1, 18, 18, 15, 23, 19, " ", 15, 6, " ", 15, 21, 20, 18, 1, 7, 5, 15, 21, 19, " ", 6, 15, 18, 20, 21, 14, 5, " ", 15, 18, " ", 20, 15, " ", 20, 1, 11, 5, " ", 1, 18, 13, 19, " ", 1, 7, 1, 9, 14, 19, 20, " ", 1, " ", 19, 5, 1, " ", 15, 6, " ", 20, 18, 15, 21, 2, 12, 5, 19, ",", " ", 1, 14, 4, " ", 2, 25, " ", 15, 16, 16, 15, 19, 9, 14, 7, " ", 5, 14, 4, " ", 20, 8, 5, 13, "?"} Javascript, 81 74 ""+[].map.call(prompt(),function(c){a=c.charCodeAt(0);return a>65&&a<123?a&31:c}) With the input taken from a variable ""+[].map.call(s,function(c){a=c.charCodeAt(0);return a>65&&a<123?a&31:c}) Output from the string you chose 8,5,18,5,',19, ,1,14,15,20,8,5,18, ,5,24,1,13,16,12,5,,, ,9, ,8,15,16,5, ,20,8,1,20, ,20,8,9,19, ,23,9,12,12, ,9,12,12,21,19,20,18,1,20,5, ,13,25, ,16,15,9,14,20,!, ,9,6, ,9,20,',19, ,21,14,1,2,12,5,,, ,13,15,18,5, ,19,16,5,3,19, ,23,9,12,12, ,2,5, ,7,9,22,5,14,.  | Word | Char | Delimiters| , , | , |  • “All other characters must be kept intact.” – You also encoded the punctuations. – manatwork Aug 8 '13 at 7:47 • @manatwork Oops, Thanks! i have missed that part, fixing it. – C5H8NNaO4 Aug 8 '13 at 7:55 C# - 137 Characters This code assumes the string to convert is the s variable Regex.Replace(Regex.Replace(s.ToUpper(),@"[A-Z]",m=>(((int)m.Value[0])-64).ToString()+'-'),@"[^\w\s-]",m=>m.Value+'-').Replace("- "," ");  Q, 53 {1_ssr[-3!($'x)^$(.Q.a!($)1+(!)26)@(_)x;"";"  "]}


Backtick Delimited

q){1_ssr[-3!($'x)^$(.Q.a!(\$)1+(!)26)@(_)x;"";"  "]}"Here's another example, I hope that this will illustrate my point! If it's unable, more specs will be given."
"85185'19  11415208518  52411316125,  9  815165  208120  208919  2391212  91212211920181205  1325  161591420!  96  920'19  211412125,  1315185  19165319  2391212  25  7922514."