Take CR and LF literally

22

3

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.


Adám

Posted 2018-05-09T08:12:35.507

Reputation: 37 779

28Suggested answer: Notepad, 179712 bytes – Nit – 2018-05-09T08:57:37.860

3@Nit :| notepad isn't TC – ASCII-only – 2018-05-09T08:58:04.400

2Shame that TIO doesn't use a proper terminal, otherwise a nice shell winner would be stty -onlcr;cat. – Toby Speight – 2018-05-09T11:28:07.243

@TobySpeight Then there would be no challenge. – Adám – 2018-05-09T11:30:33.467

1I'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? – Toby Speight – 2018-05-09T13:09:07.077

1@TobySpeight You'll probably need to input them as JSON or something similar. You don't need to count any wrapper that handles that bit. – Adám – 2018-05-09T13:12:13.820

In my opinion, just require the output to only contain only printable ASCII and newlines should be OK. – user202729 – 2018-05-09T13:48:56.540

STDERR (i.e. TIO's Debug) is also fine. And if they somehow can be wrapped (e.g. using Bash on TIO) to capture the output, that's fine too (and the wrapper doesn't need to be counted). Otherwise they cannot participate. Sorry. – Adám – 2018-05-09T13:49:36.593

2@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. – mbomb007 – 2018-05-09T21:46:38.273

Answers

6

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.

Neil

Posted 2018-05-09T08:12:35.507

Reputation: 95 035

Shouldn't you remove the l flag from your TIO link? – Adám – 2018-05-09T14:14:21.457

@Adám What's to stop me pasting any gibberish into my answer and then linking to a suboptimal program? – Neil – 2018-05-09T14:15:57.857

I see. Maybe Charcoal should output the TIO link to stderr (Debug)? – Adám – 2018-05-09T14:23:23.443

@Adám I'll suggest that to@ASCII-only. – Neil – 2018-05-09T14:37:00.127

@Neil fixed, I think? – ASCII-only – 2018-05-09T22:30:00.660

I don't know why you asked me, It was @Adám's suggestion... – Neil – 2018-05-10T00:04:07.993

yeah but for some reason he appears not to show up in the ping list – ASCII-only – 2018-05-10T01:32:04.887

@ASCII-only OK, the CMC answer has moved to stderr, but its text is still in stdout. – Adám – 2018-05-10T05:07:03.800

@Adám yes, but that's only because of the -l option – ASCII-only – 2018-05-10T05:50:28.953

@ASCII-only The idea was that echoing of code (in short form) would be on stderr only so stdour could contain clean output from the code running. – Adám – 2018-05-10T07:53:39.777

@Adám ohhhhhh, fair enough. what about AST printing? – ASCII-only – 2018-05-10T07:57:27.530

@ASCII-only I don't know what that is. – Adám – 2018-05-10T08:07:21.517

Let us continue this discussion in chat.

– ASCII-only – 2018-05-10T08:26:57.797

5

Ruby, 24 17 bytes

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

Try it online!

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

G B

Posted 2018-05-09T08:12:35.507

Reputation: 11 099

You can drop the space between tr " I think. – Kevin Cruijssen – 2018-05-09T09:35:18.997

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. – Adám – 2018-05-09T09:37:13.150

@Adám What about some languages change nothing and works in a DOS console? – tsh – 2018-05-09T09:44:40.177

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. – Adám – 2018-05-09T09:54:55.720

it won't work if the terminal was set to raw mode

– phuclv – 2018-05-09T13:09:39.640

5Changing the spec: I don't think it's fair. but I will delete my answer if I have to. – G B – 2018-05-09T13:50:39.613

@LưuVĩnhPhúc If the terminal is in raw mode, I think the input will generate the required output, so no code needed. That's exactly why I had to prohibit other output methods than through TIO. – Adám – 2018-05-09T13:51:54.377

4

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

Kevin Cruijssen

Posted 2018-05-09T08:12:35.507

Reputation: 67 575

3

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

TFeld

Posted 2018-05-09T08:12:35.507

Reputation: 19 246

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. – Lynn – 2018-05-09T10:44:31.950

3

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!

tsh

Posted 2018-05-09T08:12:35.507

Reputation: 13 072

3

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]);
}

Toby Speight

Posted 2018-05-09T08:12:35.507

Reputation: 5 058

chars are just small ints, they should be interchangeable (in theory). Maybe gcc will do an implicit cast – Stan Strum – 2018-05-09T18:51:49.873

91 bytes. – Jonathan Frech – 2018-05-11T14:37:34.340

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. – Jonathan Frech – 2018-05-11T14:40:55.327

For your interest, the relevant meta post.

– Jonathan Frech – 2018-05-14T11:01:26.587

It's now a reusable function. – Toby Speight – 2018-05-14T11:35:05.303

2

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)

ovs

Posted 2018-05-09T08:12:35.507

Reputation: 21 408

2

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.

Οurous

Posted 2018-05-09T08:12:35.507

Reputation: 7 916

1I think ?_[]=[] can be ?_ e=e. – Laikoni – 2018-05-11T07:02:07.653

@Laikoni You're right. I swear I've missed exactly that same thing a dozen times by now. – Οurous – 2018-05-11T07:03:56.307

1

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).

aoemica

Posted 2018-05-09T08:12:35.507

Reputation: 793

1You can define an infix function instead of c, use l$r instead of c 0 0r and c _ _ e=e (or rather (_#_)e=e). – Laikoni – 2018-05-11T07:15:12.340

All together 87 bytes: Try it online!

– Laikoni – 2018-05-11T07:15:58.390

@Laikoni Thank you, I didn't realize you could use that infix trick with that many parameters. – aoemica – 2018-05-11T14:02:55.110