26
\$\begingroup\$

Sometimes in chat, if someone says something you agree with, you'll send a message with an ^, which points at the message above:

Radvylf: Cats are far superior to JavaScript
You: ^

Sometimes you'll also add some text:

Radvylf: I sure do like integers
You: I mostly agree with ^ but floats are pretty neat too

You can also use multiple ^s to refer to messages farther back:

Timmy: Puppies are adorable.
Radvylf: I hate puppies.
You: ^^

In this challenge, given a chat log with ^s, you'll replace the ^s with the messages they refer to.

Task:

Given a multiline string of messages (without usernames), or an array where each message is a string (or some representation of one), resolve all of the ^ references in it. Note that messages can refer to messages that themselves have ^s, which need to be properly resolved.

For example:

Cats are funny sometimes
^
^^, but I've met serious cats too.
^^
Opinions on static typing?
It's okay.
^ It depends on the implementation, though.
^ Big difference between good and bad static ty
^ping
Thanks ^_^

This would become:

Cats are funny sometimes
Cats are funny sometimes
Cats are funny sometimes, but I've met serious cats too.
Cats are funny sometimes
Opinions on static typing?
It's okay.
It's okay. It depends a lot on the implementation, though.
It's okay. It depends a lot on the implementation, though. Big difference between good and bad static ty
It's okay. It depends a lot on the implementation, though. Big difference between good and bad static typing
Thanks It's okay. It depends a lot on the implementation, though. Big difference between good and bad static typing_It's okay. It depends a lot on the implementation, though. Big difference between good and bad static typing

You'll never need to resolve a group of ^s that points up more times than there are messages to point at. E.g., ^ will never be the first line, and ^^ will never be the second.

Test cases:

Input:

a

Output:

a

Input:

a
^b
^^

Output:

a
ab
a

Input:

a
^b
^c
^ ^^ ^^^

Output:

a
ab
abc
abc ab a

Other:

This is , so shortest answer in bytes per language wins.

\$\endgroup\$
5
  • 4
    \$\begingroup\$ I don't think ^ :) \$\endgroup\$
    – l4m2
    Mar 11, 2022 at 0:01
  • 1
    \$\begingroup\$ Oh wow this barely stayed on the sandbox at all \$\endgroup\$
    – Seggan
    Mar 11, 2022 at 0:14
  • \$\begingroup\$ ooh i like this, the next logical step of course is a chat program that implements the shortest answer to this :P \$\endgroup\$
    – des54321
    Mar 11, 2022 at 1:32
  • \$\begingroup\$ very interesting challenge! (and hard to come up with) brilliant radvylf! \$\endgroup\$
    – DialFrost
    Mar 11, 2022 at 5:57
  • \$\begingroup\$ as a cat I can confirm that we are much more interesting than JS \$\endgroup\$
    – Ginger
    Mar 19, 2022 at 14:23

13 Answers 13

12
\$\begingroup\$

JavaScript (ES6), 56 bytes

Expects and returns an array of strings.

a=>a.map((s,i)=>a[i]=s.replace(/\^+/g,s=>a[i-s.length]))

Try it online!

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Darn, had prepared this exact same solution (except using other letters for the variables). \$\endgroup\$
    – Adám
    Mar 12, 2022 at 21:15
12
\$\begingroup\$

brainfuck, 240 bytes

+>>,[[->+<<+>]>----------[+[-<+++>]<+[[-]<.>>,>>>>]<[[[<]<]+[[>]>]<<,[->+++>+<<]+++++[->-----<]>-[[-]<<[[<]<]>>->[.[[>]>]>[->+<]<<+[[<]<]<+>>>-[[[>]>]<<+[[<]<]<+>>>-]>]<<<<[[->>>+<<<]<]>>>+[[>]>->>]<+[-<+>]>>]>[[-]<<+>]<]]<<[.[-]>>>+>>,>]<]

Try it online!

Now works with blank lines. This ended up saving bytes, and the slightly altered tape structure allowed the two other improvements I had tried earlier to save bytes as well.

The tape structure of this program is as follows:

1 firstline 0 0 0 1 secondline 0 0 0 ... 1 lastline 0 input

The 1 cell at the beginning of each line allows the program to cope with empty lines and lines beginning with ^ without additional effort. It also allowed me to shorten the gap between text lines, which saved a small number of bytes.

With formatting and comments:

Initialize tape with first line marker and input
+>>,

While there is input:
[

  Duplicate input
  [->+<<+>]

  Test for newline
  >----------

  If not newline:
  [

    Test for ^ (94)
    +[-<+++>]<+

    If anything else:
    [

      Output letter and take next input
      [-]<.>>,

      Move so rest of loop will end at next input cell
      >>>>

    ]

    If caret    
    <[

      Place 1 between text lines to track which line to copy
      [[<]<]+[[>]>]<<

      Duplicate next input and check if caret
      (there's probably a shorter way to do this)
      ,[->+++>+<<]+++++[->-----<]>-

      If not another caret:
      [

        Clear test cell
        [-]

        Move to start of line to copy and delete the 1 from it
        <<[[<]<]>>->

        For each letter in that line:
        [

          Output
          .

          Move next input cell to the right
          [[>]>]>[->+<]

          Populate cell to copy to; start backup copy too
          <<+[[<]<]<+>>>-

          Copy letter to (next letter in current line) and (backup 3 left)
          [[[>]>]<<+[[<]<]<+>>>-]

        >]

        Restore line and initial 1 cell
        <<<<[[->>>+<<<]<]>>>+

        Clear indicators between lines
        [[>]>->>]

        Move input to correct cell
        (that cell contains negative one from the previous loop)
        <+[-<+>]

      >>]

      If was another caret:
      >[

        Delete input and set indicator to repeat caret loop
        [-]<<+>

      ]

  <]]

  If newline:
  <<[

    Output newline
    .

    Set up next line
    [-]>>>+>>,>

  ]

<]
\$\endgroup\$
6
\$\begingroup\$

Jelly,19 18 17 bytes

ɓŒgċ”^ịṭʋ€Ṛ}Fṭðƒḟ

Try it online!

-1 thanks to Jonathan Allan

-1 thanks to Jonathan Allan again

Takes and returns lists of lines.

              ð ḟ    Starting with the input without any of its elements,
               ƒ     reduce by:
ɓ                    with reversed arguments: (line on left, lines on right)
 Œg                  Runs of consecutive equal elements.
        ʋ€           For each run:
       ṭ             append the run to
           }         the accumulated lines
          Ṛ          reversed
      ị              and get the item at the 1-index of
   ċ”^               the number of carets.
            F        Flatten the runs and substitutions back together,
             ṭ       and append to the list of accumulated lines.

Love when I shave two bytes off (from ɓŒg=”^Sị⁸¹?ɗ€Ṛ}Fṭµƒ“”) in the course of writing an explanation :P

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Another one byte save can be made by indexing into the reverse of the lines so far with the current run appended (i.e. at index 0) TIO \$\endgroup\$ Mar 11, 2022 at 18:35
  • 2
    \$\begingroup\$ That is some powerful chaining. \$\endgroup\$
    – emanresu A
    May 19, 2022 at 5:06
5
\$\begingroup\$

Retina 0.8.2, 31 bytes

+1`(\^)+(?<=(.*)(?<-1>¶.*)+)
$2

Try it online! Link includes test cases. Explanation:

+1`

Replace one match at a time, repeating until all matches have been replaced. (This allows a replaced line to be referenced in a later line.)

(\^)+(?<=(.*)(?<-1>¶.*)+)

Match a number of ^s, then search back that many lines for the replacement text.

$2

Replace the ^s with the found text.

\$\endgroup\$
4
\$\begingroup\$

Python 3, 87 bytes

import re
def f(a,*q):
	for x in a:q+=re.sub("\^+",lambda k:q[-len(k[0])],x),
	return q

Try it online!

-11 bytes thanks to Unrelated String

\$\endgroup\$
6
4
\$\begingroup\$

Ruby, 57 51 bytes

->c,*q{c.map{|l|q<<l.gsub(/\^+/){|r|q[-r.size]}};q}

Try it online!

  • Saved 6 Bytes thanks to @G B

Lambda taking and returning an array of lines.

Instead of iterating the size of the array G B proposed to build the output by adding lines one by one, so that we take from that the previous (size of match) line.

We use gsub and the {|match| block form } which brings the last match every time.

\$\endgroup\$
2
  • \$\begingroup\$ 51 \$\endgroup\$
    – G B
    Mar 11, 2022 at 10:31
  • \$\begingroup\$ Really good improvement @G B , thanks! \$\endgroup\$
    – AZTECCO
    Mar 11, 2022 at 17:59
3
\$\begingroup\$

05AB1E, 18 bytes

εD'^ÃηRāR(N+¯sè:=ˆ

Input as a list of lines.

Try it online or verify all test cases.

Explanation:

ε           # Foreach of the (implicit) input-list:
 D          #  Duplicate the current line
  '^Ã      '#  Pop the copy, and only keep its "^"
     η      #  Pop and push the list of prefixes of this "^"-string
      R     #  Reverse this list of prefixes
  ā         #  Push a list in the range [1,length] (without popping)
   R        #  Reverse it to range [length,1]
    (       #  Negate each to range [-length,-1]
     N+     #  Add the 0-based loop-index to each: range [N-length,N-1]
       ¯    #  Push the global array
        s   #  Swap so the list of indices is at the top again
         è  #  Index each into the global array
  :         #  Replace all "^"-strings with these strings in the current line
   =        #  Print the modified line with trailing newlines (without popping)
    ˆ       #  Pop and add it to the global array
\$\endgroup\$
3
\$\begingroup\$

D, 100 bytes

Returns by modifying its input, exits with error.

import std;void f(string[]s){for(int i;;i++)s[i]=s[i].replaceAll!(x=>s[i-x[0].length])=`\^+`.regex;}

Try it online!


D, 97 bytes

This one returns a Range and doesn't error.

import std;
(string[]s,int i=0)=>s.map!(r=>s[i++]=r.replaceAll!(x=>s[i+~x[0].length])=`\^+`.regex)

Try it online!

\$\endgroup\$
3
\$\begingroup\$

APL (Dyalog Unicode), 43 bytes

Full program. Prompts for and prints list of strings.

⊢{(⍵⊃t)←'\^+'⎕R{t⊃⍨i-≢⍵.Match}t⊃⍨i←⍵}¨⍳≢t←⎕

Try it online!

 prompt for text from console

t← store in t

 tally of texts

indices 1 through that

{ apply the following anonymous lambda to each text; argument is :

i←⍵ store argument as i

t⊃⍨ pick that element from the input

'\^+'⎕R{}Replace each run of carets with:

  ⍵.Match the match

   the length of that

  i- subtract that from i

  t⊃⍨ pick that element from the input

(⍵⊃t)← in-place update the argument'th element of t with that (and implicitly return it)

 return (and implicitly print) that

\$\endgroup\$
2
\$\begingroup\$

SNOBOL4 (CSNOBOL4), 106 bytes

	T =TABLE()
I	X =X + 1
	I =INPUT	:F(END)
R	I SPAN('^') . K =T[X - SIZE(K)]	:S(R)
	T[X] =OUTPUT =I	:(I)
END

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Lua, 83 bytes

s=...;for i,l in ipairs(s)do print((l:gsub("%^+",function(m)return s[i-#m]end)))end

Must be loaded as a "chunk" (file or string). Expects input as table of strings. Prints output.

\$\endgroup\$
2
\$\begingroup\$

C++ (gcc), 191 186 181 bytes

#import<regex>
int f(std::string*a,int n){for(int b=0,c,i;b<n;++b)for(i=-1;++i<a[b].size();c?a[b].replace(i-c,c,a[b-c]),i+=a[b-c].size()-c:0)for(c=0;a[b][i]==94;++c)++i;}

Try it online!

Dang, this is bad. Only wins the Brainfuck answer lol.

For anyone trying to help here's the ungolfed code:

#include <iostream>
#include <vector>
#include <string>

void chat_reference(std::vector<std::string> &chat)
{
    for(int list_message = 0; list_message < chat.size(); ++list_message)
    {
        int reference_counter = 0;
        for(int i = 0; i < chat[list_message].size(); ++i)
        {
            while(chat[list_message][i] == '^')
            {
                ++reference_counter;
                ++i;
            }
            if(reference_counter > 0)
            {
                chat[list_message].replace(i - reference_counter, reference_counter, chat[list_message - reference_counter]);
                i += chat[list_message- reference_counter].size() - reference_counter;
                reference_counter = 0;
            }
        }
    }
}

-6 bytes thanks to ceilingcat

-4 bytes thanks to ceilingcat

-11 bytes thanks to ceilingcat

\$\endgroup\$
0
2
\$\begingroup\$

Charcoal, 51 43 bytes

WS«⊞υω≔⁰θF⪪⁺ιψ^¿κ«⊞υ⁺⁺⊟υ⎇θ§υθω⁻κψ≔±¹θ»≦⊖θ»υ

Try it online! Link is to verbose version of code. Takes input as a list of newline-terminated lines. Explanation:

WS«

Repeat for each line.

⊞υω

Add a new empty output line to the predefined empty list.

≔⁰θ

Start with no ^s.

F⪪⁺ιψ^

Append a null character to the input line, split the result on ^s and loop over the pieces.

¿κ«

If this piece is not empty, then...

⊞υ⁺⁺⊟υ⎇θ§υθω⁻κψ

... remove the last line, concatenate a previous line if there were ^s accumulated, concatenate the split piece without any null characters, and add it back to the list of lines (the indexing for the previous line works because the last line isn't in the array during the concatenation); then...

≔±¹θ

... set the number of ^s to 1 assuming that there's a following piece that was separated from this piece with a ^.

»≦⊖θ

Empty pieces correspond to consecutive ^s so simply increment the number of ^s.

»υ

Output the final list of lines.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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