62
\$\begingroup\$

I recently created a new language called ;# (pronounced "Semicolon Hash") which only has two commands:

; add one to the accumulator

# modulo the accumulator by 127, convert to ASCII character and output without a newline. After this, reset the accumulator to 0. Yes, 127 is correct.

Any other character is ignored. It has no effect on the accumulator and should do nothing.

Your task is to create an interpreter for this powerful language!

It should be either a full program or a function that will take a ;# program as input and produce the correct output.

Examples

Output: Hello, World!
Program: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#

Output: ;#
Program: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#

Output: 2d{ (unprintable characters here; should have 4 `\000` bytes between the `d` and the `{` and 3 after the `{`)
Program: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;hafh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;f;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;###ffh#h#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ffea;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#au###h;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;h;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;o

Output: Fizz Buzz output
Program: link below

Output: !
Program: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#

Fizz Buzz up to 100

Leaderboard

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

/* Configuration */

var QUESTION_ID = 121921; // Obtain this from the url
// It will be like https://XYZ.stackexchange.com/questions/QUESTION_ID/... on any question page
var ANSWER_FILTER = "!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";
var COMMENT_FILTER = "!)Q2B_A2kjfAiU78X(md6BoYk";
var OVERRIDE_USER = 48934; // This should be the user ID of the challenge author.

/* App */

var answers = [], answers_hash, answer_ids, answer_page = 1, more_answers = true, comment_page;

function answersUrl(index) {
  return "https://api.stackexchange.com/2.2/questions/" +  QUESTION_ID + "/answers?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + ANSWER_FILTER;
}

function commentUrl(index, answers) {
  return "https://api.stackexchange.com/2.2/answers/" + answers.join(';') + "/comments?page=" + index + "&pagesize=100&order=desc&sort=creation&site=codegolf&filter=" + COMMENT_FILTER;
}

function getAnswers() {
  jQuery.ajax({
    url: answersUrl(answer_page++),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      answers.push.apply(answers, data.items);
      answers_hash = [];
      answer_ids = [];
      data.items.forEach(function(a) {
        a.comments = [];
        var id = +a.share_link.match(/\d+/);
        answer_ids.push(id);
        answers_hash[id] = a;
      });
      if (!data.has_more) more_answers = false;
      comment_page = 1;
      getComments();
    }
  });
}

function getComments() {
  jQuery.ajax({
    url: commentUrl(comment_page++, answer_ids),
    method: "get",
    dataType: "jsonp",
    crossDomain: true,
    success: function (data) {
      data.items.forEach(function(c) {
        if (c.owner.user_id === OVERRIDE_USER)
          answers_hash[c.post_id].comments.push(c);
      });
      if (data.has_more) getComments();
      else if (more_answers) getAnswers();
      else process();
    }
  });  
}

getAnswers();

var SCORE_REG = /<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/;

var OVERRIDE_REG = /^Override\s*header:\s*/i;

function getAuthorName(a) {
  return a.owner.display_name;
}

function process() {
  var valid = [];
  
  answers.forEach(function(a) {
    var body = a.body;
    a.comments.forEach(function(c) {
      if(OVERRIDE_REG.test(c.body))
        body = '<h1>' + c.body.replace(OVERRIDE_REG, '') + '</h1>';
    });
    
    var match = body.match(SCORE_REG);
    if (match)
      valid.push({
        user: getAuthorName(a),
        size: +match[2],
        language: match[1],
        link: a.share_link,
      });
    
  });
  
  valid.sort(function (a, b) {
    var aB = a.size,
        bB = b.size;
    return aB - bB
  });

  var languages = {};
  var place = 1;
  var lastSize = null;
  var lastPlace = 1;
  valid.forEach(function (a) {
    if (a.size != lastSize)
      lastPlace = place;
    lastSize = a.size;
    ++place;
    
    var answer = jQuery("#answer-template").html();
    answer = answer.replace("{{PLACE}}", lastPlace + ".")
                   .replace("{{NAME}}", a.user)
                   .replace("{{LANGUAGE}}", a.language)
                   .replace("{{SIZE}}", a.size)
                   .replace("{{LINK}}", a.link);
    answer = jQuery(answer);
    jQuery("#answers").append(answer);

    var lang = a.language;
    if (/<a/.test(lang)) lang = jQuery(lang).text();
    
    languages[lang] = languages[lang] || {lang: a.language, user: a.user, size: a.size, link: a.link};
  });

  var langs = [];
  for (var lang in languages)
    if (languages.hasOwnProperty(lang))
      langs.push(languages[lang]);

  langs.sort(function (a, b) {
    if (a.lang > b.lang) return 1;
    if (a.lang < b.lang) return -1;
    return 0;
  });

  for (var i = 0; i < langs.length; ++i)
  {
    var language = jQuery("#language-template").html();
    var lang = langs[i];
    language = language.replace("{{LANGUAGE}}", lang.lang)
                       .replace("{{NAME}}", lang.user)
                       .replace("{{SIZE}}", lang.size)
                       .replace("{{LINK}}", lang.link);
    language = jQuery(language);
    jQuery("#languages").append(language);
  }

}
body { text-align: left !important}

#answer-list {
  padding: 10px;
  width: 290px;
  float: left;
}

#language-list {
  padding: 10px;
  width: 290px;
  float: left;
}

table thead {
  font-weight: bold;
}

table td {
  padding: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b">
<div id="answer-list">
  <h2>Leaderboard</h2>
  <table class="answer-list">
    <thead>
      <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr>
    </thead>
    <tbody id="answers">

    </tbody>
  </table>
</div>
<div id="language-list">
  <h2>Winners by Language</h2>
  <table class="language-list">
    <thead>
      <tr><td>Language</td><td>User</td><td>Score</td></tr>
    </thead>
    <tbody id="languages">

    </tbody>
  </table>
</div>
<table style="display: none">
  <tbody id="answer-template">
    <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>
<table style="display: none">
  <tbody id="language-template">
    <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr>
  </tbody>
</table>

\$\endgroup\$
  • 1
    \$\begingroup\$ Is it acceptable if an interpreter doesn't terminate its execution at the end of the input but instead keeps looping indefinitely without producing extra output? \$\endgroup\$ – Leo May 22 '17 at 9:26
  • 5
    \$\begingroup\$ The second example makes me wonder about a program to encode a program to produce an output... recursive compilation! \$\endgroup\$ – frarugi87 May 22 '17 at 9:29
  • \$\begingroup\$ @Leo yes that's fine \$\endgroup\$ – caird coinheringaahing May 22 '17 at 14:46
  • 1
    \$\begingroup\$ @iamnotmaynard Semicolon Hash \$\endgroup\$ – caird coinheringaahing May 23 '17 at 15:09
  • 2
    \$\begingroup\$ Maybe Wink Hash would be easier to say \$\endgroup\$ – James Waldby - jwpat7 May 23 '17 at 17:42

110 Answers 110

1
\$\begingroup\$

Mathematica, 81 bytes

StringReplace[a=0;#,{";":>(a++;""),"#":>FromCharacterCode@Mod[a,a=0;127],_:>""}]&

Pure function expecting a string argument.

Explanation

The basic evaluation procedure (it can be more complicated) for an expression in Mathematica is to evaluate the head of the epxression, then evaluate each of its arguments in order, then apply any definitions, then evaluate the entire expression again until nothing changes.

So first we evaluate StringReplace (no-op). The first argument is a=0;#, which sets the accumulator a to 0 and returns the first argument (denoted #) to the function. The second argument is a list of string replacement rules, which are applied in order starting at the beginning of the string.

If we encounter the substring ";", we replace it with (a++;""). Since we used :> instead of ->, this replacement expression is only evaluated whenever we actually find a match for ";". It (post-)increments a and returns the empty string, so finding a match for ";" effectively increments the accumulator and deletes the semicolon. In the case of a match, we move to the next position in the string, otherwise we check the next rule in the list.

If we encounter the substring "#", we replace it with FromCharacterCode@Mod[a,a=0;127]. FromCharacterCode does what you expect, but Mod[a,a=0;127] can be tricky if you don't understand Mathematica's evaluation procedure. We evaluate Mod (no-op), then evaluate the first argument a to get the value of the accumulator. When we evaluate the second argument a=0;127, we reset the accumulator to 0 and return 127. Thus we end up with Mod[<a>,127], where <a> is whatever the value of a was before the expression started evaluating. The only way I can think of to get this to work by resetting the accumulator after calculating the modulus without introducing additional variables is something like "#":>Reap[Sow[FromCharacterCode[Mod[a,127]]];a=0][[2,1,1]]. Introducing another variable I could do something like "#":>(b=a;a=0;FromCharacterCode[b~Mod~127]).

If we reach the last replacement rule, we replace any single character _ with the empty string "".

|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Rip, 33 chars

0gDiW[D';EI[Pi0]'#EI[27pdMo0]gDi]

Got around to testing this, and this works with the given examples.

|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Common Lisp, 89 bytes

(do((a 0))(())(case(read-char)(#\;(incf a))(#\#(princ(code-char(mod a 127)))(setf a 0))))

Try it online!.

This is an actual interpreter.

|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Proton, 66 bytes

a=>''.join(map(len+((%)&127)+chr,a.rstrip(';').split('\#'))[to-1])

Try it online!

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ This is the one of the first challenges you found to answer? :P \$\endgroup\$ – totallyhuman Aug 17 '17 at 19:45
  • \$\begingroup\$ @totallyhuman hey why not :P \$\endgroup\$ – HyperNeutrino Aug 17 '17 at 19:57
1
\$\begingroup\$

Bash + coreutils + dc, 93 bytes

tr ';#' '69'|tr -dc '69'|dc -e '?0sa[10~rdZ1<P]dsPx[6=Ala127%P0sa]sR[la1+saq]sA[lRxz0<M]dsMx'

Try it online!

First time submitting a multi-utility answer, so if I botched that let me know - but just treating it as bash seems the least generous in terms of byte count anyway.

I thought this would be fun to do in dc, but obviously dc does not really care for strings, so the first thing to do was use tr to translate it into a new dialect, 69 which is just ;# only... well, sixes and nines. After doing that, we also use tr to delete everything that isn't a 6 or a 9 so that we don't have to account for errant characters in dc.

With a giant number input into dc, we can make an interpreter. 0sa clears the accumulator, a. [10~rdZ1<P]dsPx uses the divide-returning-both-quotient-and-remainder command, ~ to break our big number into a stack full of individual commands. Jump to the end, the main macro [lRxz0<M]dsMx executes macro R until the stack is empty. Macro R is [6=Ala127%P0sa]sR, which tests if the top-of-stack is a 6 and runs macro A if so. Macro A has a quit command in it, which essentially makes the rest of R an else statement. This does the mod 127, Print ASCII, and reset accumulator a to zero operations. Meanwhile, macro A is just a simple increment operation for the accumulator: [la1+saq]sA.

You can try just the dc portion online!

|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Coconut, 59 bytes

t->''.join(map(x->chr(x.count(';')%127),t.split('#')[:-1]))

Try it online!

|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Haskell, 66 bytes

f s|(a,_:b)<-span(/='#')s=toEnum(mod(sum[1|';'<-a])127):f b|1<3=[]

Try it online!

  • f takes a string s as input and looks for the first # with (a,_:b)<-span(/='#')s, which splits s in the part a before the first # and b everything after.
  • sum[1|';'<-a] counts the number of ; in a which is converted into the corresponding character by toEnum after taking it modulo 127.
  • f b recursively processes the rest of the string.
  • The pattern match (a,_:b)<-span(/='#')s fails if no # exists anymore, in which case in the second pattern guard 1<3=[] the empty list is returned.
|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Julia 1.0, 90 62 bytes

i(s)=print.(Char.(count.(==(';'),split(s,"#")[1:end-1]).%127))

Try it online!

|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

C# 7572 + 18 = 9390 Bytes

using System.Linq;
s=>string.Join("",s.Split('#').Select(p=>(char)(p.Count(c=>c==59)%127)))

-3 Bytes thanks to @Charlie

Ungolfed full program with test cases

using System.Linq;

class P
{
    static void Main()
    {
        System.Func<string, string> f =
            s => string.Join("",                  //6. Combine results with empty string as separator
                s.Split('#')                      //1. Split the input by #
                    .Select(                      //2. For each part
                        p => (char)(              //5. Convert to character
                            p.Count(c => c == 59) //3. Count of all ;
                            % 127)                //4. Mod 127
                    ));

        System.Console.WriteLine(f(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#"));
        System.Console.WriteLine(f(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#"));
        System.Console.WriteLine(f(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;hafh;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;f;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;###ffh#h#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ffea;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#au###h;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;h;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;o"));
        System.Console.WriteLine(f(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#"));
    }    
}
|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ I've just come up with this same answer by myself, only to see that you posted it before. You can save 3 bytes using Count instead of Sum. Note that the last ; does not count. \$\endgroup\$ – Charlie Sep 6 '18 at 9:13
  • \$\begingroup\$ s.Split('#') gives an extra letter in the second example. Note that last substring has not # at end. \$\endgroup\$ – mazzy Sep 6 '18 at 13:12
  • \$\begingroup\$ I made the same solution and then I found yours. You can save 6 bytes if you won't join the string, but create an array of chars with ToArray(). \$\endgroup\$ – Jirka Picek Jan 23 at 10:11
1
\$\begingroup\$

PowerShell, 67 65

-join$(switch("$input"|% t*y){';'{$a++}'#'{[char]($a%127);$a=0}})

Fairly straightforward with not many surprising twists.

  • 2018-09-06: Shorter way of converting the string to a character array.
|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Nice expression with switch. \$\endgroup\$ – mazzy Sep 6 '18 at 12:43
1
\$\begingroup\$

Gol><>, 20 18 bytes

Credit to Jo King.

iE;:`#=q$o`;=+`~P%

Try it online!

How it works

iE;:`#=q$o`;=+`~P%
                    Accumulator (m) is stored at the bottom
iE;                 Take input (n) as char; halt if EOF
   :`#=q            If n == '#'... (preserving n on the top)
        $o            Output m as char, discarding it
          `;=+      If n == ';', increment m
              `~P%  m = m % 127
                    Repeat indefinitely

Previous submission, 20 bytes

iE;:`#=Q$`~P%o|`;=?P

Try it online!

How it works

iE;:`#=Q$`~P%o|`;=?P

                      Accumulator (m) is always stored at the bottom
iE;                   Take input (n) as char, halt if EOF
   :`#=Q      |       If n == '#'... (preserving n on the top)
        $`~P%o        Swap m to the top, output m%127 as char
               `;=?   If n == ';'... (discarding n; m is exposed to the top)
                   P  Increment m
                      Repeat indefinitely
|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Backhand, 37 bytes

}>_oi!{:0v] @! |{^:v-"%";"#""-"|{]~.

Try it online!

As usual with Backhand programs, I'm pretty sure this could be golfed further, but to do so would require some restructuring.

Explanation

Note that by default the pointer moves three steps at a time

}>                 Start on the second character
    i  :  ]  ! |{  Get input and check if it is EOF
            @      Reflect and terminate if so
                  :  "  ;  "  - |{     Check if the character is a ;
                                   ~.  If so, pop the extra copy of the character
                      %  "    "  [    Increment by 1 and modulo by 127
                 ^ v    Decrement the pointer step value by one and then increment it again to skip the |{
 >_  !  0  And restart the loop
                                |      If it is not a ;, reflect
                    -  "  #  "         Check if it is a #
         v   !   ^   Increment pointer and decrement again
}>_o  !{    Output if the character was a # and restart the loop
|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

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

s=>s.Split('#').Select(x=>(char)(x.Count(y=>y==59)%127)).ToArray()

Try it online!

|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

APL, 41 bytes/chars

{⎕AV[⍋⎕NXLATE 0][127|≢¨⌽⊂⍨⌽2=⍵(⊢⍳∩)';#']}

Explanation:

vector of ASCII characters

{⎕AV[⍋⎕NXLATE 0]                          }

select elements from that vector

{                 [                         ]}

keep only characters from the stream belonging to the set ';#'

{                 [               ⍵(  ∩)';#']}

find position of each character of the stream in the set ';#'

{                 [               ⍵(⊢⍳ )';#']}

0 where there's ';' and 1 where there's '#'

{                 [             2=          ]}

reverse the stream, partition beginning at every 1, reverse back; note that trailing ';'s get discarded this way

{                 [       ⌽⊂⍨⌽            ]}

length of each partition modulo 127

{                 [127|≢¨                   ]}
|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

PHP, 84 79 70 1 + 63 = 64 bytes

for(;$c=$argn[$i++];$a+=$c==";")$c^A^R||$a=~-print chr($a%127);

Run as pipe with -nR

Try it online!

|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

CJam, 18 bytes

q'#/{';e=127%c}%);

Try it online!

Explanation

q                  "Take the whole input as a single string";
 '#/               "Split the input string with hashes";
                   "This counts the empty results";
                   "According to the challenge empty results can only be";
                   "generated from trailing #'s";
    {         }%   "Map every ; sequence in the string:";
     ';e=          "Count the semicolons"
         127%      "Find the remainder of the length w/ 127";
             c     "Convert to a character"
                ); "There is a trailing null string designed for this check";
                   "If there isn't a trailing null string (i.e.)";
                   "program doesn't end with #, this removes the last item of the list";
                   "Implicit flatten the list & print as string";
|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Packed Pyth, 14 bytes

Hex dump: AD 43 1F 7B 88 F8 43 4A BE 75 C7 6C 59 37

Try it online!

Pyth, 16 bytes

VPcw\#pC%/N\;127

Try it online!

Python equivalent:

for N in input().split('#')[:-1]:
    print(end=chr(N.count(';') % 127))

Token by token explanation:

VPcw\#pC%/N\;127
V                 # for N in                        :
   w              #          input()                      # take one line of input
  c \#            #                 .split('#')
 P                #                            [:-1]      # discard last element
          N       #                N
         / \;     #                 .count(';')
        %    127  #                             % 127
       C          #            chr(                  )
      p           #  print(end=                       )   # print without trailing newline

After doing this, I looked at the other Pyth answers and found that KarlKastor's also got 16 bytes. However, I believe my answer is more correct, as it does not print a trailing newline. Since every ;;;;;;;;;;# in the input results in outputting a newline, an extra one should not be added at the end.

Funnily enough, we also both made an imperative version. Mine comes in at 25 bytes:

VwIqN\;=%hZ127)IqN\#pC~Z0

Try it online!

Python equivalent:

Z=0
for N in input():
    if N==';': Z = (Z % 127) + 1
    if N=='#': print(end=chr(Z)); Z=0
|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Burlesque, 19 bytes

'#;;{';CN127.%L[}\m

Try it online!

'#;;     # Split strings at #s
{
 ';CN    # Count the number of ; in each
  127.%  # Mod 127
  L[     # Convert to char
}\m      # Map and concatenate
|improve this answer|||||
\$\endgroup\$
1
\$\begingroup\$

Prolog (SWI), 104 bytes

It worked out to be shorter to write directly to stdout inside the predicate. The more idiomatic way of implementing something like this in Prolog would be to have third parameter for the predicate which would be the output from interpreting the program.

+A:-string_codes(A,B),0+B.
A+[E|T]:-E=35,!,C is A mod 127,put_code(C),0+T;E=59,!,B is A+1,B+T;A+T.
_+[].

Try it online!

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ You can remove the mod by matching against 127+X (my prolog terminology might be off) \$\endgroup\$ – user41805 Jan 24 at 17:20
1
\$\begingroup\$

PHP, 56 75 bytes

foreach(explode('#',$argn,-1)as$c)echo chr((count_chars($c,1)[59]??0)%127);

Try it online!

Thanks to @Umbrella for the nudge. Actually read the question and bug fixed.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ This will echo a non-printable character at the end. Pass -1 to explode to fix. \$\endgroup\$ – Umbrella Jan 24 at 21:45
0
\$\begingroup\$

F#, 165 162 bytes

-3 bytes, thanks to Random User

let g a=
 let mutable b=0
 let mutable d=""
 for c in a do
  if c=';' then
  b<-b+1
  elif c='#' then
  d<-[|d;string(char(b%127))|]|>Array.fold(+)""
  b<-0
 d

It's basically a port of my C# answer.

|improve this answer|||||
\$\endgroup\$
  • 2
    \$\begingroup\$ let golf a? golf?! Why? \$\endgroup\$ – caird coinheringaahing May 21 '17 at 19:38
  • \$\begingroup\$ @RandomUser I don't know, but I shortened it. \$\endgroup\$ – Horváth Dávid May 21 '17 at 19:40
0
\$\begingroup\$

Python 3, 66 bytes

a=0
for c in input():a-=a*(c=='#'!=print(end=chr(a%127)))-(c==';')

Try it online!

|improve this answer|||||
\$\endgroup\$
0
\$\begingroup\$

Java 8, 112 bytes

This expression is a Consumer<String>, so it assumes s is a String.

(s)->{int i=0;for(char c:s.toCharArray()){if(c==';')i++;else if(c=='#'){System.out.print((char)(i%127));i=0;}}};
|improve this answer|||||
\$\endgroup\$
0
\$\begingroup\$

AHK, 83 bytes

Loop,Parse,1
{f:=A_LoopField
If(f=";")
i++
If(f="#"){
Send % Chr(Mod(i,127))
i=0
}}

By default, Loop,Parse will parse each character individually.


I had a 76 bytes version based on splitting the input on # but, as pointed out by manatwork as a comment, it'll print the very last section even without a # at the end.

Loop,Parse,1,#
Send % Chr(Mod(StrLen(RegExReplace(A_LoopField,"[^;]")),127))
|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ Sure this prints only on #? I mean, sure ;;#;;; will result #2 and not #2#3? \$\endgroup\$ – manatwork May 22 '17 at 13:15
  • \$\begingroup\$ @manatwork Good point. I had to rewrite it at the expense of 7 bytes. Thanks. \$\endgroup\$ – Engineer Toast May 22 '17 at 13:42
0
\$\begingroup\$

Ruby, 71 50 bytes

$*[0].split(?#).each{|p|$><<(p.count(?;)%127).chr}

Edit: Complete rewrite. manatwork's solution is still shorter, but this does it a slightly different way!

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ You can replace $><<(xxx).chr with putc xxx for -5 bytes. \$\endgroup\$ – Jordan Dec 16 '17 at 17:32
0
\$\begingroup\$

Fourier, 32 bytes

$(I~Q{59}{&A}Q{35}{A%127a0~A}&i)

Try it on FourIDE!

Enter the program between quotation marks.

Explanation Pseudocode

While i != Input length
    Q = Pop character off start of string and get char ASCII code
    If Q = 59 Then
        Increment A
    End If
    If Q = 35 Then
        Convert A mod 127 to character and Print
        A = 0
    End If
    Increment i
End While
|improve this answer|||||
\$\endgroup\$
0
\$\begingroup\$

Actually, 20 bytes

'#@s⌠';@c7╙D@%c⌡MdXΣ

Try it online!

Explanation:

'#@s⌠';@c7╙D@%c⌡MdXΣ
'#@s                  split on "#"
    ⌠';@c7╙D@%c⌡M     for each chunk:
     ';@c               count occurrences of ";"
         7╙D@%          mod by 127 (2**7-1)
              c         convert to ASCII char
                 dX   discard last item
                   Σ  concatenate
|improve this answer|||||
\$\endgroup\$
0
\$\begingroup\$

Add $p=";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#"; to actually enjoy this tasty script. ($p is the input variable)

PowerShell, 98 bytes

[char[]]$p|%{if($_-eq';'){$o++}elseif($_-eq'#'){Write-Host -NoNewLine ([char]($o%127));[int]$o=0}}

Try it online!

|improve this answer|||||
\$\endgroup\$
0
\$\begingroup\$

JavaScript (ES6), 71 Bytes

p=>([...p].map(v=>v==";"?i++:b+=String.fromCharCode(i,i=0),i=0,b=""),b)

This can probably be golfed, but I think the concept passing extra arguments to functions is one of the reasons why JavaScript is one of the more interesting languages to golf in.

|improve this answer|||||
\$\endgroup\$
  • \$\begingroup\$ This seems to insert spaces between each character of the output nor does it look like it ignores invalid characters. \$\endgroup\$ – Shaggy May 29 '17 at 12:05
0
\$\begingroup\$

java, 86 95 bytes

this is a lambda expression assignable to a Consumer<String>

s->{for(String t:s.split("#|[^#]*\\Z"))System.out.print((char)(t.split(";",-1).length-1%127));}

Explanation:

  • split the input using # as the delimiter and ignore everything after the last match
  • for each substring, count the number of ;'s and output the count as a char
|improve this answer|||||
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.