challenge 条件を満たす行を取り除く

ファイルから1行ずつ読み込み、"#"で始まる行だけを取り除いてファイルに出力するコードを書いてください。

サンプル入力

hello!
# remove this
 # don't remove this
bye!
サンプル出力
hello!
 # don't remove this
bye!

Posted feedbacks - Nested

Flatten Hidden
1
2
3
while ARGF.gets
  puts $_ unless $_[0] == ?#
end
考え方は同じですが,Rubyっぽくなるように心がけてみました
1
2
3
ARGF.read.each_line do |line|
	puts line unless line.index('#') == 0
end
1
print grep!/^#/,<>
ワンライナーで
1
% ruby -ne 'puts $_ unless $_ =~ /^#/'
細かい点ですが、問題に与えられた条件では「ファイルから1行ずつ読み込み」とありますよね。この「読み込み」の部分に引っかりを感じました。Ruby に限ったことではありませんが、ワンライナーの場合、そもそも「読み込み」の部分が記述されいなことになります。ワンライナーの場合は「読み込み」ではなく、「処理」が1行ずつされることが保証されているだけですよね。。。。
実行するとfile.txtは書き換わってしまうので注意
1
vim -c "%g/^#/d _|wq" file.txt
細かい点ですが、問題に与えられた条件では「ファイルから1行ずつ読み込み」とありますよね。この「読み込み」の部分に引っかりを感じました。Vimに限ったことではありませんが、ワンライナーの場合、そもそも「読み込み」の部分が記述されいなことになります。ワンライナーの場合は「読み込み」ではなく、「処理」が1行ずつされることが保証されているだけですよね。。。。
ワンライナーです。
1
ruby -pe "next if /^#/"

	
1
2
import fileinput
map(open("out.txt", "w").write, filter(lambda v: not v.startswith("#"), fileinput.input()))
Script系はさすがに短いなぁ…
closeしてないけどreaderだから許して?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import java.io.*;

public class RemoveLine {
	public static void main(String args[]) {
		if (args.length < 1) return;
		
		try {
			BufferedReader reader = new BufferedReader(new FileReader(args[0]));
			String line = reader.readLine();
			while (line != null) {
				if (!line.startsWith("#"))
					System.out.println(line);
				line = reader.readLine();
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}
久々にC言語。エラー処理をたくさん書かないといけなかったのがC言語なんだよな。Perlはor dieですむから困る。 ……すんません、ろくに例外処理してません。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <stdio.h>
#include <stdlib.h>

#define MAXLENGTH 80

int main( int argc, char *argv[] )
{
        FILE *fh_input;
        FILE *fh_output;

        char line[MAXLENGTH];

        if ( argc != 3 ) {
                printf( "%s <input> <output>\n", argv[0] );
                exit(1);
        }

        fh_input = fopen( argv[1], "r" );
        if( fh_input == NULL ) {
                printf( "%s: file open error!\n", argv[1] );
                exit(1);
        }

        fh_output = fopen( argv[2], "w" );
        if( fh_output == NULL ) {
                printf( "%s: file open error!\n", argv[2] );
                exit(1);
        }

        while( fgets( line, MAXLENGTH, fh_input ) != NULL ) {
                if( line[0] != '#' ) {
                        fputs( line, fh_output );
                }
        }

        fclose( fh_output );
        fclose( fh_input );

        exit(0);
}
「Perlはor dieですむ」。。。C言語でも、die 関数定義すれば、いいのでは? 整数型として定義して、va_list, va_start, va_end なんか使えば、とっても面倒くさいけど、定義できますよ。いちど die 定義すれば便利につかえますから、やってみてもいいかもですね。 http://homepage2.nifty.com/mattsan/software/samples/sample034.html
PHP4以下なら普通にfopenとかで
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php
function removeComment($infile, $outfile, $startwith ='#') {
    $r = "";
    foreach(file($infile) as $line) {
        if (strncmp($line, $startwith, strlen($startwith))) {
            $r .= $line;
        }
    }
    file_put_contents($outfile, $r);
}
1
main = getContents >>= putStr . unlines . filter (('#' /=) . head) . lines

空行に対応していなかったので書き直し

1
2
3
4
main = getContents >>= mapM_ putStrLn' . lines

putStrLn' ('#':_) = return ()
putStrLn' xs = putStrLn xs
ファイルの入出力はリダイレクションを利用。
Pythonのリストは遅延評価しないので、その場で評価され中身が実行される。
1
2
import sys
[l.startswith('#') or sys.stdout.write(l) for l in sys.stdin]
すでにほとんど同じものがありますが :)
1
2
3
4
5
6
module Main (main) where
main :: IO ()
main = putStr . unlines . filter (null ||| ('#'/=) . head) . lines =<< getContents
infixr 2 |||
(|||) :: (a -> Bool) -> (a -> Bool) -> (a -> Bool)
(p ||| q) x = if p x then True else q x
lambdaがいやだったので、any-predなんぞを使ってみました。
1
2
#!/usr/local/bin/gosh
(port-for-each (any-pred #/^#/ print) read-line)
この発想はなかった。
コマンドラインオプションなしで
1
gets$9;gsub /^#.+$/,""
出力しなよ!
awk '!/^#/ {print}' ./data.txt > ./data2.txt
1
!/^[^#]/ {print;}
コピペミス
1
!/^#/ {print}
{print} なしでもいけるはず。。。
1
awk '!/^#/'
細かい点ですが、問題に与えられた条件では「ファイルから1行ずつ読み込み」とありますよね。この「読み込み」の部分に引っかりを感じました。AWK に限ったことではありませんが、ワンライナーの場合、そもそも「読み込み」の部分が記述されいなことになります。ワンライナーの場合は「読み込み」ではなく、「処理」が1行ずつされることが保証されているだけですよね。。。。(っと、自分の出した投稿に対して、後から突っ込みいれたりして。。。)
これはひどい
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
$handle = fopen('hoge.txt','r');
while(!feof($handle)){
	$buffer = fgets($handle);
	if(substr($buffer,0,1) != '#'){
		$array[] = $buffer;
	}
}
fclose($handle);
file_put_contents('hoge.txt',$array)
?>
使用例: (erase-commen-out-line 入力ファイル 出力ファイル)
1
2
3
4
5
6
7
8
9
(defun erase-comment-out-line (infile outfile)
  (with-open-file (in infile :direction :input)
    (with-open-file (out outfile :direction :output
					    :if-exists :supersede)
      (do ((line (read-line in nil 'eof)
		 (read-line in nil 'eof)))
	  ((eql line 'eof) 'Done)
	(unless (equal (schar line 0) #\#)
	  (write-line line out))))))
正規表現でやろうとしたけど、うまくいかなかった。 行頭を拾うのってどうすればいいんだっけ?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# -*- coding: utf-8 -*-

infile = open("intext.txt", "r")
s = infile.read()
infile.close()

outfile = open("outtext.txt", "w")

for x in s.splitlines():
    if x[0] != "#":
        outfile.write(x + "\n")

outfile.close()
行頭は^。 処理の中身を想像すると、正規表現内で否定を拾うより、ifの否定でやったほうが効率が良い気がする。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# -*- coding: utf-8 -*-
import re

infile = open("intext.txt", "r")
s = infile.read()
infile.close()

outfile = open("outtext.txt", "w")

for x in s.splitlines():
    if re.compile("^[^#]").search(x):
        outfile.write(x + "\n")

outfile.close()
なんでマイナス評価付いてるんだろう~
と思ったけど、プラス評価するほどでもないので評価はスルーで。

・readしてsplitしなくてもfileオブジェクトはイテレータ
・正規表現のコンパイルは重い処理なのでループの外へ

頭にシャープがあるかないかだけだから
正規表現を使うまでもない気もするけれど。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import re

infile = file("tmp.txt")
outfile = file("tmpout.txt", "w")
pat = re.compile("^[^#]")

for line in infile:
    if pat.match(line):
        outfile.write(line)

infile.close()
outfile.close()
ゆるせるワンライナー。
・ジェネレーター内包表現でコメント行を捨てる
・ファイルを変数に代入しないのでcloseはGC時に自動的に
1
2
3
4
5
file("tmpout.txt", "w").write(
    "".join(
        line
        for line in file("tmp.txt")
        if line[0] != "#"))
ゆるせないワンライナー

・リスト内包表現で副作用のある関数を呼ぶのは嫌い
 ・素直にfor文で書いた方がいい
1
2
3
[file("tmpout.txt", "w").write(line)
 for line in file("tmp.txt")
 if line[0] != "#")]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
using System;
class Program
{
  static void Main()
  {
    string s;
    while ((s = Console.ReadLine()) != null)
      if (!s.StartsWith("#")) Console.WriteLine(s);
  }
}
grep はないの?
grep -v '^#' のほうが美しいと思うけど。 
1
sed '/^#/d' file >file2
grepが言語なのかどうかが怪しいですよね
(sedが言語なのかどうかもかなり怪しいですけど、
sedスクリプトの存在とチューリング完全であるところから、
まぁ、言語に位置づけてもよいかな、と。)

言語一覧にない言語は「Other」を選んで
タグで「grep」などとつけて投稿してもOKですよ
この場合は言語「Bash」を選ぶという手もあるかと思いますが。
何気にwith文。多分Python2.5以降限定。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from __future__ import with_statement
import sys

def convert(input, output):
    with open(output, "w") as io:
        for line in open(input):
            if not line.startswith("#"):
                io.write(line)

if __name__ == '__main__':
    convert(sys.argv[1], sys.argv[2])
何の変哲もないですが・・・
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <fstream>

void convert(const char* input, const char* output)
{
    std::ifstream fin(input);

    if (fin)
    {
        std::ofstream fout(output);

        std::string s;

        while (std::getline(fin, s))
        {
            if (s.empty() || s[0] != '#')
            {
                fout << s << std::endl;
            }
        }
    }
}

int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        std::cerr << "usage: input output" << std::endl;

        return -1;
    }

    convert(argv[1], argv[2]);

    return 0;
}
前投稿したのがあまり面白くなかったので、自前で行分解するイテレータを作ってSTLしてみました。(行数かさばってすみません(汗))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <iterator>
#include <functional>

class line_iterator : public std::iterator<std::input_iterator_tag, std::string>
{
    std::istream* _in;
    std::string _line;

    void getline()
    {
        if (_in && !std::getline(*_in, _line))
        {
            _in = NULL;
        }
    }

public:
    explicit line_iterator(std::istream& in) : _in(&in) { getline(); }

    line_iterator() : _in(NULL) {}

    const std::string& operator*() const { return _line; }

    line_iterator& operator++()
    {
        getline(); return *this;
    }

    line_iterator operator++(int)
    {
        line_iterator tmp = *this; getline(); return tmp;
    }

    friend bool operator==(const line_iterator& lhs, const line_iterator& rhs)
    {
        return lhs._in == rhs._in;
    }

    friend bool operator!=(const line_iterator& lhs, const line_iterator& rhs)
    {
        return lhs._in != rhs._in;
    }
};

struct starts_with_sharp : std::unary_function<std::string, bool>
{
    bool operator()(const std::string& s) const
    {
        return !s.empty() && s[0] == '#';
    }
};

int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        std::cerr << "usage: input output" << std::endl;

        return -1;
    }

    std::ifstream fin(argv[1]);

    std::ofstream fout(argv[2]);

    std::remove_copy_if(
        line_iterator(fin),
        line_iterator(),
        std::ostream_iterator<std::string>(fout, "\n"),
        starts_with_sharp()
    );

    return 0;
}
Common Lispで初めてfile入出力書いてみたw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(require :iterate)
(in-package :iter)
(defun remove-comments (in out)
  (iter (for line in-stream in using #'read-line)
        (unless (char= (aref line 0) #\#)
          (write-line line out))))

(defun test ()
  (with-open-file (in "10.input" :direction :input)
    (with-open-file (out "10.output" :direction :output :if-exists :supersede)
      (remove-comments in out))))

(test)
stream_get_lineバージョン
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php

$handle = fopen("odai10.txt", "r");
while(!feof($handle))
{
    $buffer = stream_get_line($handle, 4096, "\n");
    if(strpos($buffer, "#") !== 0 )
    {
        $array[] = $buffer;
    }
}
fclose($handle);
file_put_contents("odai10.txt", implode("\n", $array));
?>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
my $tmp = <<"EOM";
hello!
# remove this
 # don't remove this
bye!
EOM

open(OUT,">output");

for(grep {!/^#/} split /\n/,$tmp){
	print OUT "$_\n"
}
close(OUT);