# Decode the Dreaded Alphabet Cypher™️

This challenge is inspired by one of my other challenges: Pointlessly make your way down the alphabet

That challenge asked you to take a string of text, and for each letter produce a sequence of letters moving down the alphabet to 'a'.

For this challenge I'd like to decode the output of that challenge (minus the line breaks), to find a human-readable string from a much longer human readable string.

Here is some text which has been encoded using the Dreaded Alphabet Cypher™️

It consists of descending alphabetical sequences, ending in an 'a'. The first character in each of these sequences is a letter in the decoded text. (A space is still a space).

# The challenge

• Write code to convert a Dreaded Alphabet Cypher™️ encoded string into a decoded, human-readable string.
• No need to validate if it is a Dreaded Alphabet Cypher™️ string, I'm not interested in how it handles invalid input.
• Use any language you please.
• The input will only consist of lower-case letters and spaces. No upper cases, punctuation etc.
• Code golf, try to write short code, standard loopholes etc.

# Test Cases

Input:

hgfedcbaedcbalkjihgfedcbalkjihgfedcbaonmlkjihgfedcba wvutsrqponmlkjihgfedcbaonmlkjihgfedcbarqponmlkjihgfedcbalkjihgfedcbadcba


Output:

hello world


Input:

abacbadcbaedcbafedcbagfedcbahgfedcbaihgfedcbajihgfedcbakjihgfedcbalkjihgfedcbamlkjihgfedcbanmlkjihgfedcbaonmlkjihgfedcbaponmlkjihgfedcbaqponmlkjihgfedcbarqponmlkjihgfedcbasrqponmlkjihgfedcbatsrqponmlkjihgfedcbautsrqponmlkjihgfedcbavutsrqponmlkjihgfedcbawvutsrqponmlkjihgfedcbaxwvutsrqponmlkjihgfedcbayxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcba


Output:

abcdefghijklmnopqrstuvwxyz


(beware the multiple a's)

Input:

aarqponmlkjihgfedcbaonmlkjihgfedcbanmlkjihgfedcba a aarqponmlkjihgfedcbaonmlkjihgfedcbanmlkjihgfedcbasrqponmlkjihgfedcbaonmlkjihgfedcbanmlkjihgfedcba hgfedcbaasrqponmlkjihgfedcba anmlkjihgfedcba aarqponmlkjihgfedcbadcbavutsrqponmlkjihgfedcbaarqponmlkjihgfedcbakjihgfedcba


Output:

aaron a aaronson has an aardvark


Input:

hgfedcbaaponmlkjihgfedcbaponmlkjihgfedcbayxwvutsrqponmlkjihgfedcba gfedcbaonmlkjihgfedcbalkjihgfedcbafedcbaihgfedcbanmlkjihgfedcbagfedcba


Output (is a secret, shh)

• May the input contain leading or trailing spaces, or several spaces in a row? – Arnauld Nov 29 '19 at 14:17
• @Arnauld I'm happy with trailing and leading spaces, but not within the result itself. – AJFaraday Nov 29 '19 at 14:19
• Sorry, I meant the input, not the output. (I've edited my previous comment.) – Arnauld Nov 29 '19 at 14:20
• @Arnauld The input could have trailing and leading spaces. – AJFaraday Nov 29 '19 at 16:43
• @JonathanAllan sounds fine to me – AJFaraday Nov 29 '19 at 19:12

# JavaScript (ES9),  37 33  26 bytes

Returns an array of characters.

Either a negative look-behind:

s=>s.match(/(?<![b-z])./g)


Try it online!

Or a positive look-behind:

s=>s.match(/(?<=a| |^)./g)


Try it online!

## 25 bytes

If the input is guaranteed not to contain leading or double spaces (or we're allowed to remove and collapse them respectively), the positive look-behind can be made 1 byte shorter:

s=>s.match(/(?<=a|\b)./g)


Try it online!

f s=[y|(x,y)<-zip('a':s)s,x<'b']


Try it online!

For each pair of consecutive characters, if the first one is 'a' or ' ', output the second one. Prepends an 'a' to the string so that the first character is always output.

# Jelly, 6 bytes

OŻI‘Tị


A monadic Link accepting a list of characters which yields a list of characters.

Try it online!

### How?

OŻI‘Tị - Link: list of characters, S   e.g. "  baadcba  acbaedcba  "
i.e. [' ',' ','b','a','a','d','c','b','a',' ',' ','a','c','b','a','e','d','c','b','a',' ',' ']
O      - to ordinal (vectorises across S)   [ 32, 32, 98, 97, 97,100, 99, 98, 97, 32, 32, 97, 99, 98, 97,101,100, 99, 98, 97, 32, 32]
Ż     - prepend a zero                 [  0, 32, 32, 98, 97, 97,100, 99, 98, 97, 32, 32, 97, 99, 98, 97,101,100, 99, 98, 97, 32, 32]
I    - incremental differences            [ 32,  0, 66, -1,  0,  3, -1, -1, -1,-65,  0, 65,  2, -1, -1,  4, -1, -1, -1, -1,-65,  0]
‘   - increment (vectorises)             [ 33,  1, 67,  0,  1,  4,  0,  0,  0,-64,  1, 66,  3,  0,  0,  5,  0,  0,  0,  0,-64,  1]
T  - truthy indices                     [  1,  2,  3,      5,  6,             10, 11, 12, 13,         16,                 21, 22]
ị - index into (S)                     [' ',' ','b',    'a','d',             ' ',' ','a','c',       'e',                ' ',' ']


# Perl 5 (-p), 15, 16 bytes

s/[b-z]\K.*?a//g


Try it online!

or using options trick

# Perl 5 (-nF/(?<![\x20a])(?!^)[b-z]*a/), 7 bytes

print@F


Try it online!

# Python 3, 43 bytes

lambda s:[r for l,r in zip(' '+s,s)if'b'>l]


An unnamed function accepting a string which returns a list of characters.

Try it online!

To accept & return lists use ...zip([' ']+s... instead (45)

To accept & return strings use lambda s:''.join(r for l,r in zip(' '+s,s)if'b'>l) (50)

# C (clang), 1009896959492908864 46 bytes

Saved 24 bytes thanks to @Neil!!!
Saved 18 bytes thanks to @dingledooper (removed #include<stdio.h>)

f(char*c){while(*c)for(putchar(*c);*c++>97;);}


Try it online!

• Why not just while(*n>97)? – Neil Nov 30 '19 at 20:41
• Also, by putting putchar(*c); before the while loop, I was able to replace all uses of n with c. – Neil Nov 30 '19 at 20:46
• In fact, by changing the while loop into a for loop you can move the putchar(*c) into the initialiser, saving you a pair of {}s. – Neil Nov 30 '19 at 20:47
• @Neil Thanks so much, that's amazing! And now I can finally have a post-increment as part of the condition expression. :-) – Noodle9 Nov 30 '19 at 22:26
• Thanks for posting this; the loop structure was useful for an x86 machine code implementation – Peter Cordes Dec 2 '19 at 6:48

# J, 22 13 12 bytes

–9 bytes, thanks @Jonah!

#~1,1-{:I.}:


Try it online!

• 13 bytes: #~1,98>3 u:}: (Try it online!) – Jonah Dec 1 '19 at 13:15

# 05AB1E, 9 8 bytes

-1 byte thanks to Kevin Cruijssen

AηíR¬S.:


Try it online!

• 8 bytes by replacing ASR with ¬S. – Kevin Cruijssen Nov 29 '19 at 14:47
• @KevinCruijssen Nice catch, thanks! – Grimmy Nov 29 '19 at 14:54

# Japt-g, 109 8 bytes

óÈ¥YcÄÃy


Try it

ó           split between those characters that return true when passed through...
È    Ã     function :
¥         x equal to..
YcÄ      character next to y
y   transpose

Flag -g used to get 1st element


Saved 1 thanks to @Shaggy

• 1dYc can be YcÄ – Shaggy Nov 29 '19 at 16:47
• I don't know why ó> or ò< won't work here; was trying them earlier. – Shaggy Nov 29 '19 at 16:49
• I was trying something similar too but nothing worked – AZTECCO Nov 29 '19 at 17:30
• – Shaggy Nov 29 '19 at 18:35
• @Shaggy i moved to japt chat – AZTECCO Nov 29 '19 at 19:32

# R, 57 56 bytes

-1 byte thanks to Giuseppe.

function(s)intToUtf8(c(v<-utf8ToInt(s),0)[c(0,v)%%32<2])


Try it online!

Could probably be made shorter with a regex, but this is more R-like. Converts to integers (vector v), then keeps only the first character and the characters which follow a space or an a. Since the corresponding codepoints are 32 and 97, we can check whether $$\v_i\mod 32 <2\$$ to get the relevant entries.

• 56 bytes using in-line assignment instead of a function argument – Giuseppe Dec 2 '19 at 20:57
• @Giuseppe Thanks! – Robin Ryder Dec 2 '19 at 21:09

f""=""
f(x:s)|x<'b'=x:(f s)|1>0=x:(f$tail$dropWhile(>'a')s)


Try it online!

No match for regex solutions, but I figured I'd try a recursive solution.

# JavaScript, 3532 31 bytes

s=>s.replace(/ |.*?a/g,x=>x[0])


Try it online!

# Ruby, 28 bytes

->s{s.scan(/(?<=a|\b)./)*""}


Try it online!

This is a port of Arnauld's Javascript answer to Ruby.

# K (oK), 14 bytes

{x@&1,98>-1_x}


Try it online!

Inspired by FrownyFrog's/Jonah's J solution

# Japt-S, 9 8 bytes

¸®ò§ mÎ¬


Try it

¸®ò§ mÎ¬    :Implicit input of string
¸           :Split on spaces
®          :Map
ò         :  Partition between characters where
§        :  First is <= second
m      :  Map
Î     :    First character
¬    :  Join
:Implicit output, joined with spaces


# Jelly, 10 bytes

Ḳµ=Ṃk⁸ZḢ)K


Try it online!

A monadic link taking a Jelly string and returning a Jelly string. When run as a full program takes a string as its argument and implicitly prints the output string.

# SNOBOL4 (CSNOBOL4), 106 bytes

	I =INPUT
S	I LEN(1) . X	:F(O)
O =O X
R =
REVERSE(&LCASE) X REM . R
I X R REM . I	:(S)
O	OUTPUT =O
END


Try it online!

	I =INPUT			;* Read input
S	I LEN(1) . X	:F(O)		;* extract the first letter or goto O if none exist
O =O X				;* append that letter to the output
R =				;* set R to the empty string
REVERSE(&LCASE) X REM . R	;* Set R to the letters up to 'a', starting at X.
;* R is empty string if X is space or 'a'
I X R REM . I	:(S)		;* Set the REMainder of I after (X + R) to I; goto S
O	OUTPUT =O			;* output the string
END


# Red, 74 bytes

func[s][parse s[any[copy t thru"a"(prin#""+ length? t)opt[sp(prin sp)]]]]


Try it online!

# braingasm, 20 18 bytes

,[.32-n[65-$[,]],]  It's been a while since I worked on braingasm. There seems to be a compare function, but I guess I didn't come around to implement a way to use the result. Well, this works: , # Read a byte from input [ ] # While the current byte is not zero . # Print it 32- # Decrease by 32 n[ ] # If the result is non-zero (meaning it wasn't a space): 65- # Subtract 65, leaving 'a' => 0, 'b' => 1, 'c' => 3, etc$[,]      #      That many times, read a byte from input


Doesn't handle newlines or anything other than lowercase letters and spaces in the input.

# Pip, 12 bytes

aR\w*?a_@0


Try it online!

### Explanation

a             The input, as a command-line argument
R            Do a regex replacement:
\w*?a      Match a non-greedy series of letters ending in a
_@0   Replace with the first character of the match


# C# (Visual C# Interactive Compiler), 33 bytes

x=>x.Where((_,l)=>l<1||x[l-1]<98)


Try it online!

# C (clang), 66 48 bytes

edit: -18 bytes thanks to @dingledooper (removed #include)

P;D(char*T){*T?P>97||putchar(*T),P=*T++,D(T):0;}


Try it online!

int P;          // previous character
D(char*T)
{
if (*T)     // check for end of string
{
if (!(P > 'a'))     // output current if previous was 'a' or ' '
putchar(*T);
P = *T;             // update previous
D(T + 1);           // find next
}
}

• You can remove the #include <stdio.h>, by the way – dingledooper Nov 30 '19 at 18:45
• @dingledooper that's interesting, I didn't know that C allows calling standard functions without including the appropriate header. – xibu Nov 30 '19 at 19:11
• @xibu: It's not recommended, but yes C89 has default-promotion rules for what happens when calling a function for which no prototype exists. If the actual definition of the function is compatible with the args you passed it, it works. If not, UB with no detection at compile time of the mismatch. – Peter Cordes Dec 2 '19 at 2:51

# x86 machine code, 12 bytes

(Runs in any mode, 16-bit, 32-bit, or 64-bit.)

This is based on @Noodle9's C algorithm, but with rearrangement into do{}while asm loop structure.

NASM listing: address, machine code (hex dump of the actual answer), source

 1                             decda:  ; (char *dst=RDI, const char *src=RSI)
2 00000000 AC                     lodsb             ; AL = *src++
3                             .loop:                ; do{
4 00000001 AA                     stosb                 ; *dst++ = AL
5                                .skip_until_a:         ; do{
6 00000002 3C61                    cmp  al, 'a'
7 00000004 AC                      lodsb
8 00000005 77FB                    ja  .skip_until_a    ; }while((AL=*p++) > 'a')
9 00000007 84C0                   test al,al
10 00000009 75F6                   jnz .loop         ; } while(AL != terminator)
11                             ;    stosb             ; append a terminating 0
12 0000000B C3                     ret
; output end pointer returned in RDI


Try it online!

The input is an implicit-length (0-terminated) C string. The output is an explicit-length buffer. This function returns (in RDI) a pointer to one-past-the-end.

(The caller already knows where the output buf starts, so it has C++-like .begin and .end iterators). Making this function append a terminating 0 would cost 1 extra byte for another stosb after the loop, unless there's a way to rearrange things that I'm not seeing.

A sample caller that passes the output of decda(argv[1]) to a write system call is included in the TIO link. You can inc edx in that caller to prove that the output didn't over-write beyond where it's supposed to.

I had been thinking of using loop .loop instead of test al,al/jnz but then the inner loop would need a dec ecx or something. (Without that, it loops until writing RCX output bytes, which only works if the caller knows the decrypted length, not the source length.) Worth considering for a 32-bit-only version that can use 1-byte dec ecx, unless that could reach loop or loopne with ECX<=0 for valid inputs.

• Very nice! I assembled and tested this on 16-bit MASM 1.1 and passes all tests perfectly. :) – 640KB Dec 5 '19 at 18:36
• @640KB: cool, I only tested it on x86-64 Linux. Well-golfed machine code is often independent of mode thanks to using implicit increments and sizes so I was pretty sure about my claim of working in any mode, but nice to have it tested :) – Peter Cordes Dec 5 '19 at 18:39

# C# (Visual C# Interactive Compiler), 69 bytes

Hard to beat Regex on this one

s=>System.Text.RegularExpressions.Regex.Replace(s,"([b-z]).*?a","$1")  Try it online! Returns an array of Matches (characters), 64 bytes s=>System.Text.RegularExpressions.Regex.Matches(s,"(?<![b-z]).")  Try it online! # Gema, 41 characters \A\P?=? \P?=$0
?\P?=@cmps{?;?;$2;$2;}
?=


Unfortunately recognizers can not be combined. ☹

Sample run:

bash-5.0$gema '\A\P?=$0; \P?=$0;?\P?=@cmps{$1;$2;$2;$2;};?=' <<< 'cbagfedcba cbacba' cg cc  Try it online! # Perl, 20 bytes s:[^a]*a(.):a$_\1:g;


is almost there. Unfortunately, it will lose the first letter, and I don’t know how to get around that.

• Just add an a on the beginning! "a$_" =~ .... – Will Crawford Nov 30 '19 at 13:08 • Doesn’t$ match the end of the string? And the underscore? – WGroleau Nov 30 '19 at 17:19
• $_ is the string! "a$_" is equivalent to concatenating "a" and $_ ... – Will Crawford Nov 30 '19 at 17:49 • I edited according to how I interpret your comment, but either it's wrong or I misunderstood. What I put in would make every output start with 'a'. Can you edit it so that it is correct? (Not that it competes with the length of a few others.) – WGroleau Nov 30 '19 at 19:07 • Oh, no, I meant, apply the regex to "a$_" (I'm assuming you use "perl -ne" or "perl -pe", so each line will be available as \$_). – Will Crawford Nov 30 '19 at 22:35

# Keg, -ir, -lp, 9 7 bytes

(⑩(a-|_


Try it online!

2 bytes saved thanks to @A̲̲ suggesting to use a for loop over a while loop

{!|⑩(a-|_


Try it online!

{!|⑩(a-|_
{!|             #While there are still items on the stack:
⑩            #Print t.o.s without popping
(a-|            #Subtract the code point of a from tos and repeat that many times:
_           #Pop items off the stack

• 7 bytes. A simple optimization from while to for. (Your current program also generates an error in the end, so..) – user85052 Nov 30 '19 at 12:34
• @A No, not at all. I... I wouldn't have thought of using a for loop... I was going to add a 'loop while there are still items on the stack' command to get this down to 6 bytes. – Lyxal Nov 30 '19 at 21:28

# C++, 464 bytes

I'm still a beginner so will be grateful for any advice.

#include <iostream>
#include <string>
using namespace std;

int main() {
string input , output;
getline(cin,input);
output = input[0];

for (int i = 0 ; i<input.size() ; i++) {
if (input[i] == 'a')  {
output += input[i+1];
}  else if (input[i] == ' ') {
output += input[i+1];
}  else {
continue;
}

}
cout << output;
}


Try it online!

• I don't know much about C++, but 212 bytes – Lyxal Dec 1 '19 at 5:37
• Also, welcome to CGCC! I hope you enjoy golfing answers to challenges while you're here! – Lyxal Dec 1 '19 at 5:38
• Get a warning for 159 bytes – user85052 Dec 1 '19 at 7:44
• As a first step, definitely remove all whitespace (including newline) and unneeded {}. And always use single-letter variable names. You can include an "ungolfed" version of your code in your answer (with newlines and comments) so people can read it. See also Tips for golfing in C++ – Peter Cordes Dec 2 '19 at 2:55
• The <string> header is already included in <iostream>, the number of times you need std:: is way less bytes than using namespace std;, std::string::operator[](size_t pos) will return '\0' for pos == size(). and your if statement can be collapsed to checking if the current character is less than 98('b'). 122 bytes. :-) – Noodle9 Dec 2 '19 at 14:27

# Python 3.8 (pre-release), 50 bytes

import re
f=lambda s:re.sub('([b-z]).*?a',r'\1',s)


Regex stolen from Arnauld's JavaScript answer.

Try it online!

• You can save 2 more bytes easily... – game0ver Nov 29 '19 at 13:29
• @game0ver I'm not familiar with the rules of the site, but does that count as a function? – L. F. Nov 29 '19 at 13:34
• Yes lambda is autonomous except for e.g. a recursive function where you need to refer to f... – game0ver Nov 29 '19 at 13:35
• @game0ver But you can't just do something like print((lambda s:... import re)(input())) right? – L. F. Nov 29 '19 at 13:37
• If you mean to place that all in the Footer then no. Your code must be an autonomous complete function/program. A lambda can be used standalone in a e.g. map etc... – game0ver Nov 29 '19 at 13:39

# Jelly, 20 bytes

O0;ṡ2_/>0ƊÐḟṪ€Ọ
ḲÇ€K


Try it online!

probably too long lol

# Explanation

O0;ṡ2_/>0ƊÐḟṪ€Ọ  This challenge, for one word
O                turn all the chars to their ASCII forms
0;              prepend 0
ṡ2            split into (overlapping) slices of length 2 (pairs)
Ðḟ     filter: remove elements where
_/          reducing over subtraction (which is equivalent to the first minus the second, in each pair)
>0        is greater than 0 (if it's strictly descending)
Ṫ€   take the second element of each pair
Ọ  convert back to chars
ḲÇ€K             Compiled Program
Ḳ                split on spaces
Ç€              apply the helper to each word
K             join on spaces
`