75
\$\begingroup\$

COBOL is a very old language, at the time of writing it is 58 years old. It is so old, in fact, that it has a very interesting quirk: the first six characters of each line are comments.

Why is this, you ask? Well, those 6 characters were intended to be used as line numbers, back in the day where programs weren't completely digital and typed out on a computer.

In addition, the seventh character could only be part of a very small set (it is usually * to comment out the line or a space to separate the line number from the code)

But what if you're on a more digital system, and you just want the raw program?

The comment system

There are two types of comments in COBOL: line comments and the aforementioned "line number" comments.

Uncommenting line numbers is simple: just take the first seven (six plus a single space) characters off each line.

000000 apple
000001 banana
celery donuts

would become:

apple
banana
donuts

Line comments make it a bit more difficult. A line comment is started with an asterisk * placed in the seventh character position on the line, like so:

000323* this is a comment

This is not a line comment:

*00000 this isn't a comment

To uncomment a line comment, just remove the whole line.

An example commented "program":

000000 blah blah
000001* apples
000002 oranges?
000003* yeah, oranges.
000*04 love me some oranges

The uncommented version:

blah blah
oranges?
love me some oranges

In other words, to uncomment a string, remove the first six characters of each line, then return all but the first character of every line that does not begin with a star.

The challenge

Create a program or function that takes a commented program and returns its uncommented variant.

Clarifications

  • Asterisks (*) will never be found anywhere outside the first seven characters on a line (we're not asking you to verify syntax)
  • Each line will always have at least 7 characters.
  • You may assume the seventh character is always an asterisk or a space.
  • Input or output may be a matrix or list.
  • Only printable ASCII characters (plus newline) must be handled.
  • You may output with a trailing newline. You may also assume that the input will have a trailing newline, if you so choose.

Scoring

Since this is , the answer with the least bytes wins!

DISCLAIMER: I do not actually know COBOL and do not claim to. If any of the claims about COBOL I have made in this question are incorrect, I take no responsibility.

\$\endgroup\$
18
  • 26
    \$\begingroup\$ Line numbers are not comments. They are a column. Terminology please. \$\endgroup\$
    – user207421
    Aug 24, 2017 at 5:47
  • 2
    \$\begingroup\$ Your examples all have a space after the *. Is this a coincidence? \$\endgroup\$
    – Neil
    Aug 24, 2017 at 10:13
  • 8
    \$\begingroup\$ Old does not automatically imply bad. I have worked in an Agile COBOL shop. They could do things on the AS/400 we could not do in Java. \$\endgroup\$ Aug 24, 2017 at 12:06
  • 4
    \$\begingroup\$ Can there be a space in the first 6 characters? \$\endgroup\$
    – user4768
    Aug 24, 2017 at 15:30
  • 3
    \$\begingroup\$ Column 7 in addition to a space, could also contain not only * (asterix) a comment but also - (hyphen) indicating a continuation line and / (forward slash) form feed \$\endgroup\$ Aug 27, 2017 at 6:31

62 Answers 62

2
\$\begingroup\$

Pure Bash, 42 + 1 = 43 bytes

Filename must be x; it is for extra one byte.

read x||>x
((1${x:6:1}1))||echo ${x:7}
. x

Try it online!

Usage

  • Input from stdin.
  • Optional trailing LFs.
  • Output to stdout.
\$\endgroup\$
2
\$\begingroup\$

AWK, 34 24 15 bytes

sub(/^.{6} /,_)

Attempt This Online!

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

Zsh (builtins only), 35 bytes

for l ("${(f)$(<p)}")<<<${l:7$l[7]}

Try it Online

Scans file p per this tip. Other solutions: 45 bytes, 27b (illegal)

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Aren't you supposed to input EVERY line of COBOL program, not a line of? \$\endgroup\$ Nov 19, 2022 at 23:18
  • \$\begingroup\$ Ah, good point... will need to work on it again! \$\endgroup\$
    – roblogic
    Nov 20, 2022 at 1:48
1
\$\begingroup\$

05AB1E, 11 bytes

|ʒ6èðQ}ε7F¦

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 10 bytes: |ε6.$ćðQi, \$\endgroup\$
    – Grimmy
    Sep 25, 2019 at 12:59
  • \$\begingroup\$ @Grimy Heh, .$ didn't exist back then. :P \$\endgroup\$ Sep 25, 2019 at 13:13
1
\$\begingroup\$

C++ (GCC), 121 112 bytes

Thanks to @gurka for saving 9 bytes!

#import<bits/stdc++.h>
void f(std::list<std::string>l){for(auto s:l)if(s[6]-42)std::cout<<s.substr(7,s.size());}

Takes input as a list of lines.

Try it online!

\$\endgroup\$
6
  • \$\begingroup\$ #import? Also, I think that it's OK to omit standard includes. \$\endgroup\$
    – simon
    Aug 24, 2017 at 14:05
  • 2
    \$\begingroup\$ #import isn't standard C++, but at least GCC and MSVC support it. Omitting some includes works with C, but not with C++. The code doesn't work without the includes, so they have to be counted in the total bytecount. \$\endgroup\$
    – Steadybox
    Aug 24, 2017 at 14:15
  • \$\begingroup\$ Aha, I thought you could just skip includes since you don't see any import in python answers or using in C# answers. Also, wouldn't #include <bits/stdc++.h> be shorter for your answer? \$\endgroup\$
    – simon
    Aug 24, 2017 at 14:26
  • \$\begingroup\$ @gurka Yes, it would be shorter. Thanks! \$\endgroup\$
    – Steadybox
    Aug 24, 2017 at 14:53
  • \$\begingroup\$ @gurka the imports are counted in Python answers, it's just that Python has a lot of functions that don't need importing. C# tends to not have using statement because it's generally shorter to write system.foo() than using system;foo() \$\endgroup\$
    – Pavel
    Aug 24, 2017 at 19:45
1
\$\begingroup\$

Java 8, 95 54 53 bytes

s->s.filter(x->x.charAt(6)<33).map(x->x.substring(7))

-42 bytes thanks to @OliverGrégoire, by using a Stream<String> instead of String as in- and output.

Explanation:

Try it here.

s->                          // Method with Stream<String> as parameter and return-type
  s.filter(x->x.charAt(6)<33)//  Filter out all lines containing an asterisk as 7th char
   .map(x->x.substring(7))   //  And remove the first 7 characters from the remaining lines
                             // End of method (implicit / single-line body)
\$\endgroup\$
8
  • \$\begingroup\$ Looks like you can use a String[] or List<String> as input for -12 bytes. \$\endgroup\$
    – Jakob
    Aug 24, 2017 at 17:06
  • \$\begingroup\$ Or Stream<String> if that can help. Example : s->s.map(x->x.charAt(6)!=42?x.substring(7):"") \$\endgroup\$ Aug 24, 2017 at 23:28
  • 1
    \$\begingroup\$ Oh, it's needed to filter... then s->s.filter(x->x.charAt(6)!=42).map(x->x.substring(7)) for 54 bytes. \$\endgroup\$ Aug 25, 2017 at 7:28
  • 1
    \$\begingroup\$ Use <42 instead of !=42 because "You may assume the seventh character is always an asterisk or a space." \$\endgroup\$ Aug 25, 2017 at 10:15
  • 1
    \$\begingroup\$ @OlivierGrégoire Ah, missed that rule, otherwise I would have done so myself. Thanks for the correction. \$\endgroup\$ Aug 25, 2017 at 12:08
1
\$\begingroup\$

Japt, 11 10 bytes

Takes input as an array of strings and outputs an array of strings.

k_g6 x
®t7

Test it (-R flag for visualisation purposes only)

  • Saved a byte thanks to ETH.

Explanation

Implicit input of array U.

f_

Filter (f) by passing each element through a function.

g6

Get the character at index (g) 6 (0-indexed).

x

Trim, giving either * (truthy) or an empty string (falsey).

®t7

Map (®) over the array and get the substring (t) of each element from the 7th character. Implicitly output the resulting array.

\$\endgroup\$
2
  • \$\begingroup\$ think the first line can be k_g6 x \$\endgroup\$ Aug 24, 2017 at 21:09
  • \$\begingroup\$ @ETHproductions: Today was not a good day's golfing for me - I was playing around with solutions using x, as seen in my alt. solution, and I still didn't twig that! Thanks once again :) \$\endgroup\$
    – Shaggy
    Aug 24, 2017 at 23:15
1
\$\begingroup\$

TeX - 139 bytes

\let~\def~\a#1#2#3#4#5#6{\b}~\d#1{\catcode`#1=12}\obeylines\d\ ~\b#1#2
{\if#1*\else\write1{#2}\fi\egroup
}\everypar{\bgroup\d\\\d\{\d\}\a}

Eats up the first six characters of each line, then checks if the next one is an asterisk or something else. Recurses over lines by eating up anything that tries to get typeset. The rest of my bytes are spent on changing category codes of syntax related characters so it's robust.

\$\endgroup\$
1
\$\begingroup\$

Javascript, 37 bytes

Regexp-based solution

s=>s.replace(/^.{6}( |(\*.+$\n?))/gm,'')
\$\endgroup\$
1
\$\begingroup\$

Jq 1.5, 24 bytes

select(.[6:]<"*")|.[7:]

Explanation

  select(.[6:] < "*")          # discard if '*' in column 7
| .[7:]                        # keep remaining portion

Sample run with paste to show input vs output

$ paste input <(jq -MRr 'select(.[6:]<"*")|.[7:]' input)
000000 blah blah                blah blah            
000001* apples                  oranges?                    
000002 oranges?                 love me some oranges 
000003* yeah, oranges.          
000*04 love me some oranges

$ wc -c <<<'select(.[6:]<"*")|.[7:]'
      24

Try it online

\$\endgroup\$
1
\$\begingroup\$

Dash, 26 bytes

cut -c7-|grep ^\ |cut -c2-

Try it online!


Dash, 29 bytes

cut -c7-|grep -vF \*|cut -c2-

Try it online!

OBTW it's POSIX-compatible, if I remember the specs correctly.

\$\endgroup\$
1
\$\begingroup\$

Pxem, 88 bytes (filename) + 0 bytes (content) = 88 bytes, with non-printable characters.

  • Filename (some unprintables are escaped): \001.t.i.m.+.w.i.s.i.s.i.s.i.s.i.s.i*.zAB.z.i.c.o\n.a\002.tXX.a.m\002.zAB.i\n.z.i\n.aXX.a\001.t.i.m.+.a
  • Content: empty.

Try it online!

Usage

/path/to/pxem/interpreter THAT_PROGRAM_AS_IN_ABOVE <input.txt

COBOL program to be input must be fed from stdin, with LF-styled newlines, whose last line is terminated with LF.

Alternative: Pxem, 100 bytes (filename) + 0 bytes (content) = 100 bytes, printables and LF only.

Filename is as follows:

ab.-.t.i.m.+.w.i.s.i.s.i.s.i.s.i.s.i*.zAB.z.i.c.o
.a02.-.tXX.a.mac.-.zAB.i
.z.i
.aXX.aab.-.t.i.m.+.a

Commented version

XX.z (this is just to format well
.a<0x01>.tXX.z (reg=1
.a.i.m.+.wXX.z (while getchar()!=EOF; do (obtw EOF is -1
   .a.i.s.i.s.i.s.i.s.i.sXX.z (5.times { getchar(); }
   .a.i*.zXX.z (while getchar()!='*'; do
      .aAB.z.i.c.o<0x0A>.aXX.z (do print(c=getchar()) while c!=newline
      .a<0x02>.tXX.z (reg=2
   .aXX.aXX.z ( break; done
   .a.m<0x02>.zXX.z (while reg!=2; do
      .aAB.i<0x0A>.z.i<0x0A>.aXX.z (do c=getchar() while c!=newline
   .aXX.aXX.z ( break; done
   .a<0x01>.tXX.z (reg=1
.a.i.m.+.aXX.z (done
.a
\$\endgroup\$
0
1
\$\begingroup\$

Scratch, 277 bytes.

define g[x
set[s v]to(
set[j v]to((x)+(1
repeat(length of(item(i)of[l v
set[s v]to(join(s)(letter(j)of(item(i)of[l v
change[j v]by(1
end
replace item(i)of[l v]with(s
define f
set[i v]to(1
repeat(length of[l v
g(6
if<(s)contains[*]?>then
delete(i)of[l v
else
g[1
change[i v]by(1

Try it on Scratch! enter image description here

\$\endgroup\$
1
\$\begingroup\$

K (ngn/k), 28 bytes

{$["*"=x@6;"";" "/1_" "\x]}'

Try it online!

Takes a list of strings and returns a list of strings.

Explanations:

{$["*"=x@6;"";" "/1_" "\x]}'  Main function. Takes implicit input
                           '  For each string in the lists...
{                         }   Execute a function that
 $[                      ]    Checks if
       x@6                    The character at the 6th position (0-indexed)
   "*"=   ;                   Is equal to an asterisk
           "";                If it does, return an empty string
                        x     Else, return the string
                    " "\      Splitted by whitespace
                  1_          Trim the first element (i.e. the line numbers)
              " "/            Join together by whitespace (to preserve the original text)
\$\endgroup\$
1
  • \$\begingroup\$ Save two byets by indexing into a list instead of $[]: tio \$\endgroup\$
    – naffetS
    Nov 9, 2022 at 1:17
1
\$\begingroup\$

GFortran, 84 bytes

Try it Online!

Yet again, Fortran beats Cobol ☺. Borrows stuff from this solution.

character(99)C;read*,n;do i=1,n;read'(A)',C
if(C(7:7)<'*')print'(A)',C(8:);enddo;end

Previously: 95 bytes ; 98 bytes(-47 by removing array) ; 145 bytes

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

J, 20 bytes

7&}."1(#~'*'~:6&{"1)

This assumes the input is a matrix of equal-length space-padded lines.

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

PHP, 50 bytes

foreach(file(C)as$s)$s[6]>" "||print substr($s,7);

same length:

foreach(file(C)as$s)$s[6]^a^q||print substr($s,7);
foreach(file(C)as$s)$s[6]^b^x&&print substr($s,7);
foreach(file(C)as$s)echo$s[6]^b^x?substr($s,7):"";

regex solution, 51 bytes:

<?=join(preg_filter("#^.{6} (.*)$#","$1",file(C)));

builtins only, 108 bytes:

<?=join(array_map(function($s){return substr($s,7);},array_filter(file(C),function($s){return$s[6]^b^x;})));

take code from a file named C. Run with -nr or try them online.

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

CJam, 13 bytes

{{6>'*#},7f>}

Try it online!

Explanation:

{           }  e# Block. Input:                ["000000 blah blah" "000001* apples" "000002 oranges?" "000003* yeah, oranges."]
 {     },      e# Filter on the following:
  6>           e#   Remove first 6 characters: [" blah blah" "* apples" " oranges?" "*yeah, oranges"]
    '*#        e#   Find a '*':                [-1 0 -1 0]
               e# End filter:                  ["000000 blah blah" "000002 oranges?"]
         7f>   e# Remove first 7 characters:   ["blah blah" "oranges?"]
\$\endgroup\$
0
\$\begingroup\$

Implicit, 22 bytes

('\6¯_0=`*!{]\1%ß1}]^ö

No explanation, sorry. I forgot how this works.

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

Pyth - 15

V.z*.DNU7n@N6\*

Explanation:

V.z*.DNU7n@N6\*
V.z              For each line N in input
                  Print
     N             N
   .D U7           but with characters 0-6 removed
  *                times
          @N6       Item six of N
         n          Does not equal
             \*     "*"
      
\$\endgroup\$
0
\$\begingroup\$

Husk, 9 bytes

fo≠' ←m↓7

Try it online!

same idea as Jelly.

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

Excel, 40 bytes

=FILTER(MID(A:A,8,73),MID(A:A,7,1)<>"*")

COBOL has a max line length of 80.

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

Stax, 7 bytes

ê┬|Y¶à6

Run and debug it

Explanation

m6%B42=C
m        map each line:
 6%      split at index 6, push both parts
   B     uncons, pop and push first element
    42=C if equal to 42, cancel
\$\endgroup\$
0
\$\begingroup\$

Pascal, 122 B

This is a complete program requiring a processor complying to ISO standard 10206 “Extended Pascal”:

program p(input,output);var l:string(80);begin while not EOF do begin readLn(l);if''=l[7]then writeLn(subStr(l,8))end end.

Ungolfed version with some explanatory comments:

program uncommentFixedFormatCobol(input, output);
    var
        { This “discriminates” the built-in schema data type `string`
          to have a capacity of up to 80 characters, i.e. the maximum
          width of one COBOL _fixed-format_ source code line. }
        line: string(80);
    begin
        { `EOF` is shorthand for `EOF(input)`. }
        while not EOF do 
        begin
            { `readLn(line)` is shorthand for `readLn(input, line)`. }
            readLn(line);
            { Similarly, `write(x)` is shorthand for `write(output, x)`. }
            
            { ---- Remember, in Pascal `string` indices are 1-based. ----- }
            { This may look like an empty string check, and `''` is indeed
              an empty string, yet in Pascal the `=`-comparison first pads
              both operands  to the same length using `' '`.  This line is
              in fact doing `if line[7] = ' ' then`, but one byte shorter. }
            if line[7] = '' then
            begin 
                { `subStr(line, 8)` shorthand for
                  `subStr(line, 8, length(line) - 8 + 1)` }
                writeLn(subStr(line, 8))
                { Wait! What if `line[8]` does not exist? The standard
                  says it shall be an error if `firstCharacterIndex +
                  substringLength − 1` is greater than the length of the
                  supplied string. If `length(line)` equals seven, then
                  we’re calling `subStr(line, 8, 0)` which is fine. }
            end
        end
    end.
\$\endgroup\$
0
\$\begingroup\$

C++ (gcc), 68 bytes

[](auto&l){l.remove_if([](auto&s){int c=s[6];s=&s[7];return c&2;});}

Input is a std::list<std::string>, it's modified in place.

Try it online!

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

Knight (v2), 19 bytes

W=xP|?42A=xSxF6@O]x

There are a few ways to do this that all are 19 bytes, but the theoretically optimal way (= x SUBST(PROMPT 0 6 @)) suffers from keyword clashing, meaning it has to be =xS P0 6@, wasting two separators.

# for each line in stdin
WHILE (= x PROMPT)
    #  If not equal to to 42 (ASCII("*"))
    #   |    | ASCII value of first char
    #   |    |     | Strip the first 6 chars of x
    : | ? 42 ASCII (= x SUBST (x FALSE 6 @))
      # Output the tail (all but the first char) of x
      : OUTPUT (] x)

This uses the new ] and @ operators to simplify string operations, as ] replaces SxF1"" and @ replaces "" when coerced to String since empty list is empty string.

Input is in stdin, output is in stdout.

Try it online!

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

Pyth, 12 bytes

tMfqdhT>R6.z

Try it here.

Explanation:
tMfqdhT>R6.z | Full program
-------------+----------------------------------------
        R .z | For each line of input
       > 6   |  Remove the first 6 characters
  f  hT      | Filter over whether the first character
   qd        |  is a space
tM           | Remove the first character of each
\$\endgroup\$
0
\$\begingroup\$

Pure Bash, 39 bytes

Outgolfed user100411's answer

for x
{ ((1${x:6:1}1))||echo "${x:7}"
}

Attempt This Online!

Usage

Each argument represents a line. e.g.

cat<<'EOF'>f
for x
{ ((1${x:6:1}1))||echo "${x:7}"
}
EOF
bash f '000000 blah blah' '000001* apples' '000002 oranges?' '000003* yeah, oranges.' '000*04 love me some oranges'
\$\endgroup\$
0
\$\begingroup\$

Thunno 2 N, 10 bytes

¤æ6ið=;ı7ỵ

Attempt This Online!

Explanation

¤æ6ið=;ı7ỵ  # Implicit input
¤           # Split the multi-line input on newlines
 æ    ;     # Filter this list of strings by:
  6i        #  The 6th character (0-indexed)
    ð=      #  Is a space
       ı    # Map over this new list of strings:
        7ỵ  #  Remove the first 7 characters
            # Implicit output, joined on newlines
\$\endgroup\$
0
\$\begingroup\$

sed 4.2.2, 29 bytes

/^.{6}\*.*$/d
s/^.{7}//
/^$/d

Try it online!

\$\endgroup\$

Your Answer

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

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