22
\$\begingroup\$

As a celebration of good old Notepad, we are going to treat carriage returns and line feeds as what they originally meant, rather than what they are (ab-)used for today.

Given a string consisting of printable ASCII plus line feeds (␊; LF; esc \n; hex 0A; dec 10) and carriage returns (␍; CR; esc \r; hex 0D; dec 13), cause Try It Online to show how the printable characters would be positioned if printed on a printer which takes those two control characters literally:

  1. upon a line feed, continue printing one line further down
  2. upon a carriage return continue printing from the left edge
  3. multiple consecutive carriage returns behave like a single carriage return

Due to modern devices having problems with overstriking, a run of one or more of carriage returns will, except for at the beginning of the input, never occur without at least one preceding and/or following line feed. However, two runs of carriage returns may be separated by a single line feed.

Any amount of additional trailing white space is acceptable, both on the right-hand side of any lines and below the entire text, as long as at least the amount of white space given in the input is preserved.

Examples (using \n and \r for line feed and carriage return)

Lorem ipsum dolor sit amet,

Lorem ipsum dolor sit amet,

consectetur adipiscing\nelit, sed

consectetur adipiscing
                      elit, sed

do eiusmod\r\ntempor incididunt\n\n ut labore

do eiusmod
tempor incididunt

                  ut labore

et dolore\n\rmagna \r\r\naliqua. Ut (notice the trailing spaces)

et dolore
magna          
aliqua. Ut

\nenim ad minim veniam,\n\r quis nostrud


enim ad minim veniam,
     quis nostrud

\rexercitation\r\n\rullamco laboris\n\r\nnisi ut aliquip ex\n\n\rea commodo consequat.\n\n

exercitation
ullamco laboris

nisi ut aliquip ex

ea commodo consequat.


\$\endgroup\$
  • 28
    \$\begingroup\$ Suggested answer: Notepad, 179712 bytes \$\endgroup\$ – Nit May 9 '18 at 8:57
  • 3
    \$\begingroup\$ @Nit :| notepad isn't TC \$\endgroup\$ – ASCII-only May 9 '18 at 8:58
  • 2
    \$\begingroup\$ Shame that TIO doesn't use a proper terminal, otherwise a nice shell winner would be stty -onlcr;cat. \$\endgroup\$ – Toby Speight May 9 '18 at 11:28
  • 1
    \$\begingroup\$ I'm having trouble entering the carriage-return characters into the "input" field of TIO. They just seem to get swallowed up (or converted into newlines) when pasting - is that my browser at fault, or is it TIO? \$\endgroup\$ – Toby Speight May 9 '18 at 13:09
  • 2
    \$\begingroup\$ @Adám Don't prohibit all outputs than TIO. Instead restrict programs to using certain terminal types, or to file output. Or require that output have the necessary spaces preceding text on new lines. \$\endgroup\$ – mbomb007 May 9 '18 at 21:46
6
\$\begingroup\$

Charcoal, 10 bytes

UTFθ«ι≡ι⸿↑

Try it online! Link is to verbose version of code. Explanation:

UT

Disable right padding.

Fθ«

Loop over the input.

ι

Print the current character. This automatically handles \n (which Charcoal treats as \v in this context) but Charcoal translates \r into \r\n, so...

≡ι⸿

... check for an \r...

... and if so then move back up a line.

\$\endgroup\$
  • \$\begingroup\$ Shouldn't you remove the l flag from your TIO link? \$\endgroup\$ – Adám May 9 '18 at 14:14
  • \$\begingroup\$ @Adám What's to stop me pasting any gibberish into my answer and then linking to a suboptimal program? \$\endgroup\$ – Neil May 9 '18 at 14:15
  • \$\begingroup\$ I see. Maybe Charcoal should output the TIO link to stderr (Debug)? \$\endgroup\$ – Adám May 9 '18 at 14:23
  • \$\begingroup\$ @Adám I'll suggest that to@ASCII-only. \$\endgroup\$ – Neil May 9 '18 at 14:37
  • \$\begingroup\$ @Neil fixed, I think? \$\endgroup\$ – ASCII-only May 9 '18 at 22:30
5
\$\begingroup\$

Ruby, 24 17 bytes

->s{s.tr $/,"\v"}

Try it online!

It does not work on TIO, but works on the Linux console.

\$\endgroup\$
  • \$\begingroup\$ You can drop the space between tr " I think. \$\endgroup\$ – Kevin Cruijssen May 9 '18 at 9:35
  • \$\begingroup\$ Uh, I didn't think of this solution, it may just work for any language to change all \ns into \v when run in a Linux console. \$\endgroup\$ – Adám May 9 '18 at 9:37
  • \$\begingroup\$ @Adám What about some languages change nothing and works in a DOS console? \$\endgroup\$ – tsh May 9 '18 at 9:44
  • \$\begingroup\$ I'm sorry for changing the spec mid-challenge, but to make the challenge more interesting and less subject to trivial answers, I now require proper output on TIO. \$\endgroup\$ – Adám May 9 '18 at 9:54
  • 5
    \$\begingroup\$ Changing the spec: I don't think it's fair. but I will delete my answer if I have to. \$\endgroup\$ – G B May 9 '18 at 13:50
4
\$\begingroup\$

Java 10, 211 207 206 bytes

s->{var a=s.replace("\r\n","\n\r").split("(?<=\n)");int i=0,p=0,j;for(var x:a){for(j=x.charAt(0)<14?0:p;j-->0;x=" "+x);j=(a[i++]=x.replace("\r","")).length()-1;p=x.matches("\\s+")?p:j;}return"".join("",a);}

Try it online.

Explanation:

s->{                      // Method with String as both parameter and return-type
  var a=s.replace("\r\n","\n\r")
                          //  Replace all "\r\n" with "\n\r"
        .split("(?<=\n)");//  Create String-array split by "\n",
                          //  without removing the trailing "\n" delimiter
  int i=0,                //  Index integer
      p=0,                //  Previous line-length, starting at 0
      j;                  //  Temp integer
  for(var x:a){           //  Loop over the String-array
    for(j=x.charAt(0)<14?0//   If the current line starts with either '\r' or '\n':
        0                 //    Prepend no spaces
       :                  //   Else:
        p;j-->0;x=" "+x); //    Prepand `p` amount of spaces for the current item
    j=(a[i++]=x.replace("\r",""))
                          //   Remove all "\r" from the current line
       .length()-1;       //   Set `j` to the current line-length (minus the trailing '\n')
    p=x.matches("\\s+")?  //   If the current line only contains '\r', '\n' and/or spaces:
       p                  //    Leave `p` unchanged
      :                   //   Else:
       j;}                //    Change `p` to this line-length minus 1
  return"".join("",a);}   //  Return the String-array joined together

Old answer before the challenge was changed 151 148 bytes:

s->{String a[]=s.replace("\r\n","\n\r").split("(?<=\n)"),r="";int p=0,i;for(var x:a){for(i=p;i-->0;r+=" ");i=x.length()-1;p=i<1?p:i;r+=x;}return r;}

Explanation:

s->{                            // Method with String as both parameter and return-type
  String a[]=s.replace("\r\n","\n\r") 
                                //  Replace all "\r\n" with "\n\r"
              .split("(?<=\n)"),//  Create String-array split by "\n",
                                //  without removing the trailing "\n" delimiter
         r="";                  //  Result-String, starting empty
  int p=0,                      //  Previous line-length, starting at 0
      i;                        //  Index (and temp) integer
  for(var x:a){                 //  Loop over the String-array
    for(i=p;i-->0;r+=" ");      //   Append `p` amount of spaces to the result
    i=x.length()-1;p=i<1?p:j;   //   If the current line is not empty:
                                //    Replace `p` with the length of this current line
    r+=x;}                      //   Append the current item
  return r;}                    //  Return the result-String

Doesn't work on TIO, does work on Windows Command Prompt:

enter image description here

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

JavaScript (Node.js), 85 bytes

s=>s[R='replace'](/(.*)([\n\r]+)/g,(_,t,b)=>t+b[R](/\r/g,_=>s='',s=t[R](/./g,' '))+s)

Try it online!

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

Python 2, 150 128 122 104 103 bytes

def f(s):
 i=n=0;l=''
 for c in s:l,n,i=[l,l+c,l+' '*i*n+c,n,1,0,0,i,i+1]['\r\n'.find(c)%3::3]
 print l

Try it online!


Saved:

  • -1 byte, thanks to Lynn
\$\endgroup\$
  • \$\begingroup\$ It seems l,n,i=[l,l+c,l+' '*i*n+c,n,1,0,0,i,i+1]['\r\n'.find(c)%3::3] is just barely shorter. \$\endgroup\$ – Lynn May 9 '18 at 10:44
3
\$\begingroup\$

C (gcc), 100 94 bytes

b,c,d;f(char*s){for(b=13;b;b=*s++)b==13?c=d=0:b-10?d=!printf("%*c",++d,b),++c:putchar(b,d=c);}

Assumes ASCII coding ('\r'==13, '\n'==10); adjust to suit on other systems.

Try it online! (requires Javascript)

Readable version

int c = 0;
int d = 0;

f(char*s)
{
    for (;*s;++s) {
        switch (*s) {
        case'\r':
            c = d = 0;
            break;
        case'\n':
            d = c;
            putchar(*s);
            break;
        default:
            printf("%*s%c", d, "", *s);
            d = 0;
            ++c;
        }
    }
}

c is the current column position; d is the number of spaces that must be inserted before a printable character. Both are assumed to be zero on entry to the function.

Test program

int main(int argc, char **argv)
{
    char s[1024];
    if (argc <= 1)
        while (fgets(s, sizeof s, stdin))
               f(s);
    else
        for (int i = 1;  i < argc;  ++i)
            f(argv[i]);
}
\$\endgroup\$
  • \$\begingroup\$ chars are just small ints, they should be interchangeable (in theory). Maybe gcc will do an implicit cast \$\endgroup\$ – Stan Strum May 9 '18 at 18:51
  • \$\begingroup\$ 91 bytes. \$\endgroup\$ – Jonathan Frech May 11 '18 at 14:37
  • \$\begingroup\$ By the way, I do not think that per our consensus you are allowed to reset your global variables c,d. Your function should -- without other cleanup code -- be able to run multiple times. Thus you most likely need to add a c=d=0. \$\endgroup\$ – Jonathan Frech May 11 '18 at 14:40
  • \$\begingroup\$ For your interest, the relevant meta post. \$\endgroup\$ – Jonathan Frech May 14 '18 at 11:01
  • \$\begingroup\$ It's now a reusable function. \$\endgroup\$ – Toby Speight May 14 '18 at 11:35
2
\$\begingroup\$

Python 3, 101 94 bytes

Based on TFeld's answer.

def f(s):
 i=n=0
 for c in s:k='\r\n'.find(c);a=k&1;print(end=-k*' '*i*n+c*a);n=k>0;i=i*a-k//2

Try it online!


Ungolfed

def f(s):
  i=0  # position of the cursor
  n=0  # was the last character LF?
  for c in s:        # iterate over the input
    k='\r\n'.find(c) # k := 0 for CR, 1 for LF and -1 for every other character
    a=k&1            # as (-1)&1 == (1)&1 == 1, this is a := abs(k)
    print(end=-k*' '*i*n+c*a) # If c is a normal character (k == -1) and the last character was LF, 
                              # print leading spaces. If c is not CR, print it
    n=k>0            # n := True if c is LF, False otherwise
    i=i*a-k//2       # If c is either a newline or a printable character (a == 1),
                     # keep the cursor's position and increment it for a printable character ((-1)//2 == -1)
\$\endgroup\$
2
\$\begingroup\$

Clean, 92 91 bytes

-1 thanks to Laikoni!

Note: \ in \r is omitted from bytecount as Linux CG handles literal \r and \ns.
Note: Windows CG requires \n and \r be escaped, so +3 if it has to run on Windows.

import StdEnv
?n['\r':t]= ?0t
?n['
':t]=['
':spaces n]++ ?n t
?n[h:t]=[h: ?(n+1)t]
?_ e=e

?0

Try it online!

A partial application of ? :: Int [Char] -> [Char] with 0 as the initial first argument. This descends through each character keeping track of how many traversed, the count resets when it encounters a carriage return and when it encounters a newline it adds spaces equal to the number of characters traversed at that point.

\$\endgroup\$
  • 1
    \$\begingroup\$ I think ?_[]=[] can be ?_ e=e. \$\endgroup\$ – Laikoni May 11 '18 at 7:02
  • \$\begingroup\$ @Laikoni You're right. I swear I've missed exactly that same thing a dozen times by now. \$\endgroup\$ – Οurous May 11 '18 at 7:03
1
\$\begingroup\$

Haskell, 93 87 bytes

l=0#0
(n#x)(t:r)|t=='\n'=t:(n#1)r|t=='\r'=l$r|m<-n+1=(' '<$[1..n*x])++t:(m#0)r
(_#_)e=e

Try it online!


Pretty straightforward solution. # is an infix function that recursively creates the output one character at a time while keeping a character position counter (n) and flag for when to add spaces after a newline (x).

\$\endgroup\$
  • 1
    \$\begingroup\$ You can define an infix function instead of c, use l$r instead of c 0 0r and c _ _ e=e (or rather (_#_)e=e). \$\endgroup\$ – Laikoni May 11 '18 at 7:15
  • \$\begingroup\$ All together 87 bytes: Try it online! \$\endgroup\$ – Laikoni May 11 '18 at 7:15
  • \$\begingroup\$ @Laikoni Thank you, I didn't realize you could use that infix trick with that many parameters. \$\endgroup\$ – aoemica May 11 '18 at 14:02

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.