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

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

サンプル入力

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

Posted feedbacks - Flatten

Nested Hidden
1
2
3
while ARGF.gets
  puts $_ unless $_[0] == ?#
end

1
print grep!/^#/,<>

ワンライナーで
1
% ruby -ne 'puts $_ unless $_ =~ /^#/'

実行するとfile.txtは書き換わってしまうので注意
1
vim -c "%g/^#/d _|wq" file.txt

ワンライナーです。
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);
}

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

ファイルの入出力はリダイレクションを利用。
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)

考え方は同じですが,Rubyっぽくなるように心がけてみました
1
2
3
ARGF.read.each_line do |line|
	puts line unless line.index('#') == 0
end

コマンドラインオプションなしで
1
gets$9;gsub /^#.+$/,""

出力しなよ!

awk '!/^#/ {print}' ./data.txt > ./data2.txt
1
!/^[^#]/ {print;}

コピペミス
1
!/^#/ {print}

この発想はなかった。

これはひどい
 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()

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

たこのお題の趣旨は「ファイルハンドルの扱い」×2だと思うので忠実にやってみました。

C#なのでCloseはusingに任せるが吉♪
ただしハンドルが2つの場合にこの書き方で良いのか不安(^^;
むしろ他の言語でusingの代わりにどう実装するのか見てみたいです。
(たぶんJavaならfinallyだと思うけど…)

正規表現は趣旨でないと思ったので割愛ッ!

注意:このコードを試すときは実行ディレクトリにファイルを用意するかフルパスを指定して下さい。
 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
using System;
using System.Collections.Generic;
using System.Text;

namespace FileIO
{
    class Program
    {
        static void Main(string[] args)
        {
            FileIO("sample_in.txt", "sample_out.txt");
        }

        static void FileIO(string fnameIn, string fnameOut)
        {
            using (System.IO.StreamWriter sw = new System.IO.StreamWriter(fnameOut,false,System.Text.Encoding.Default))
            {
                using (System.IO.StreamReader sr = new System.IO.StreamReader(fnameIn, System.Text.Encoding.Default))
                {
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        if (! line.StartsWith("#"))
                        {
                            sw.WriteLine(line);
                        }
                    }
                }
            }
        }
    }
}

とにかく短く書いてみた。

>php sample.php src.txt dest.txt
1
2
3
<?php
foreach(file($argv[1]) as $l)if(strpos($l,"#") !== 0)$r[]=$l;
file_put_contents($argv[2],implode("",$r));

まんまF#でやってみました。
 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
open System;;
open System.Text;;
open System.IO;;
open Array;;

let fileIO (ifname:string) (ofname:string) =
    let streamW = new StreamWriter( ofname, false, Encoding.Default ) in
    let streamR = new StreamReader( ifname, Encoding.Default ) in
    let rmCommentLn (wstream:StreamWriter) =
        let rec readf (rstream:StreamReader) =
            let line = rstream.ReadLine() in
            if line = null then ()
            else
                begin
                    if not (line.StartsWith "#")
                    then wstream.WriteLine line
                    else ();
                    readf rstream
                end
        in using streamR readf
    in using streamW rmCommentLn;;

if (length Sys.argv) = 3
then fileIO Sys.argv.(1) Sys.argv.(2)
else ();;

Squeak Smalltalk で手続き的に。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
| file out |
file := FileStream fileNamed: 'test.txt'.
out := FileStream newFileNamed: 'out.txt'.
[file atEnd] whileFalse: [
   | line |
   line := file nextLine.
   line first == $# ifFalse: [
      out nextPutAll: line.
      file peekLast == Character cr ifTrue: [out cr]]].
file close.
out edit

> cscript rem.js input.txt output.txt
 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
var objFSO = new ActiveXObject("Scripting.FileSystemObject");

function /* void */ rmComments( ifname, ofname ) {
    contents = "";
    if( objFSO.FileExists( ifname ) ) {
	ifileObj = objFSO.GetFile( ifname );
	streamR = ifileObj.OpenAsTextStream( 1 );
	streamW = objFSO.CreateTextFile( ofname );
	try {
	    while( !streamR.AtEndOfStream ) {
		contents = streamR.ReadLine();
		if( contents.search(/#/) != 0 ) {
		    streamW.WriteLine( contents );
		}
	    }
	} finally {
	    streamR.Close();
	    streamW.Close();
	}
    } else {
	throw (ifname + ": No Such File");
    }
    return;
}

var arg = WScript.Arguments.Unnamed;
rmComments( arg.Item(0), arg.Item(1) );

XSLT 2.0 でしか動きません。input パラメタに入力ファイル名を与えます。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:param name="input" />

<xsl:template match="/">
  <xsl:for-each select="tokenize(unparsed-text($input), '\r?\n')">
    <xsl:if test="not(starts-with(., '#'))">
      <xsl:value-of select="."/><xsl:text>&#xa;</xsl:text>
    </xsl:if>
  </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

ああ、タグを "XSLT 2.0" とすると2つのタグになってしまうのか…。

Javaでファイル入出力ってあんまりやったことなかったなぁ。めんどくさそうなイメージがあったから。
やってみるとやっぱりm(ry
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;

public class ExcludeComment {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new FileReader(args[0]));
        FileWriter fw = new FileWriter("result");
        String line;
        while ((line = br.readLine()) != null) {
            line = line.trim();
            if (!line.startsWith("#")) {
                fw.write(line + "\n");
            }
        }
        br.close();
        fw.close();
    }
}