コメントの削除
Posted feedbacks - Flatten
Nested Hidden一番のりを狙って書きました。起動パラメータに与えられたJavaのソースファイルからコメントを削除し、".out" 拡張子つきのファイルに書き込みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import java.util.regex.*;
import java.io.*;
public class Decomment {
static final Pattern COMMENT1 = Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL);
static final Pattern COMMENT2 = Pattern.compile("//.*");
public static void main(String[] args) throws IOException {
for (String name : args) {
BufferedReader r = new BufferedReader(new FileReader(name));
FileWriter w = new FileWriter(name + ".out");
StringBuilder sb = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
sb.append(line).append(System.getProperty("line.separator"));
}
String s1 = COMMENT1.matcher(sb).replaceAll("");
String result = COMMENT2.matcher(s1).replaceAll("");
w.write(result);
w.close();
}
}
}
|
言語仕様的には PostScript では%以降がコメントになります。 ただしプリンタや処理系によってはコメント中の情報を用いて処理をする場合があります...
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 | %!PS
/Decomment { % (filename) Decomment -
true exch
(r) file
{
% outputflag file
dup read
not { exit } if
dup 37 eq {
3 -1 roll pop false 3 1 roll
} if
dup dup 10 eq exch 13 eq or {
3 -1 roll pop true 3 1 roll
} if
2 index {
( ) dup 0 4 -1 roll put
print
} {
pop
} ifelse
} loop
pop pop
} bind def
%---- Test Code ----
(decomment.ps) Decomment
|
文字列リテラルに対応していませんでした。あわてると駄目ですね。
文字列リテラル対応版です。
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 | import java.util.regex.*;
import java.io.*;
public class Decomment {
static final String LITERAL = "\"(?:\\\\.|[^\"])*\"";
static final String COMMENT1 = "(?s:/\\*.*?\\*/)";
static final String COMMENT2 = "//.*";
static final Pattern DECOM_PAT = Pattern.compile("(" + LITERAL + ")|" +
COMMENT1 + "|" + COMMENT2);
static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static void main(String[] args) throws IOException {
for (String name : args) {
BufferedReader r = new BufferedReader(new FileReader(name));
FileWriter w = new FileWriter(name + ".out");
StringBuilder sb = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
sb.append(line).append(LINE_SEPARATOR);
}
String result = DECOM_PAT.matcher(sb).replaceAll("$1");
w.write(result);
w.close();
}
}
}
|
Squeak Smalltalk で。
与えられた Smalltalk コードを抽象構文木に落とし、それに含まれるコメントノードを削除してから文字列に戻して出力しました(実際は、抽象構文木の初回出力時にそこからコメントノードが削除される副作用を流用)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | | decomment |
decomment := [:sourceStr |
| dummySel tree |
dummySel := 'dummy '.
tree := Parser new
parse: (dummySel, sourceStr) readStream
class: UndefinedObject
noPattern: false
context: nil
notifying: nil
ifFail: [^nil].
(tree printString; printString) allButFirst: dummySel size].
^decomment value: '"comment1" ^ self "comment2"' "=> ' ^ self' "
|
Brainf*ckで。入力された文字のうち、コメント(実行可能な8文字以外全部)を削除します。終了せず、ひたすら入力を待ち続けるので適当に止めてください。
Brainfuck Developerで実行する場合は複数行の入力ができませんが、[Extras] - [Set Input File ...] から入力ファイルを指定できます。すばらしいツールです。あとは言語が良けりゃぁ言うことなし。
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 | +[>
, # {1} = input char
>+< # {2} = 1
[->>+>+<<<] # {3:4} = !{1}
>>>
>++++++[-<------->]<- # {4} = {4} minus 43
[ # if {4} not 43 (plus)
-[ # if {4} not 44 (comma)
-[ # if {4} not 45 (minus)
-[ # if {4} not 46 (dot)
>++++[-<---->]<++
[ # if {4} not 60 (lt)
--[ # if {4} not 62 (gt)
>+++++[-<------>]<+
[ # if {4} not 91 (open)
--[ # if {4} not 93 (close)
<<->> # then {2} = 0
[-]
]
]
]
]
]
]
]
]
<<
[>.<-] # if {2} then print {3}
>[-]<<
<]
|
see: Gauche:PrettyPrint
1 2 3 4 5 6 7 8 | (define decomment (lambda ()
(let loop ((s (read)))
(if (not (eof-object? s))
(begin (write s) (newline) (loop (read)))))))
(define main (lambda (args)
(decomment)
0))
|
修正版... 文字列中に%を書けたとは...
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 | %!PS
/Decomment { % (filename) Decomment -
true exch
0 exch
(r) file
{
% outputflag file
dup read
not { exit } if
dup 40 eq {
3 -1 roll 1 add 3 1 roll
} if
dup 41 eq {
3 -1 roll 1 sub 3 1 roll
} if
dup 37 eq {
2 index 0 eq {
4 -1 roll pop false 4 1 roll
} if
} if
dup dup 10 eq exch 13 eq or {
4 -2 roll pop pop true 0 4 2 roll
} if
3 index {
( ) dup 0 4 -1 roll put
print
} {
pop
} ifelse
} loop
pop pop pop
} bind def
%---- Test Code ----
(====%===) pop % ==
(decomment.ps) Decomment
|
doukaku.185.R:
------------------------------------------------------------------------
# Rのコメントは一行なので、大抵の場合はgrep("^[^#]", <文字列>, value=TRUE)で問題なさそうですが。
a <- 10 # 文頭以外のコメント
b <- "文字列中の#"
if(0){
ここに書くコメントはRの文法上のコメントではないので削除されません
}
実行結果:
------------------------------------------------------------------------
> decomment("doukaku.185.R")
expression(a <- 10, b <- "文字列中の#", if(0){
ここに書くコメントはRの文法上のコメントではないので削除されません
})
attr(,"srcfile")
doukaku.185.R
1 | decomment <- parse
|
C++で書いてみました。 が、C++を書いた気にならない... ちなみに、#if 0 ~ #endif は「コメント」ではないと思っているので対応していません。
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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #include <iostream>
#include <fstream>
/* g++ -o decomment decomment.cpp */
// decomment
void decomment(
std::ostream& os,
std::istream& is
)
{
bool blc, olc; /* in block/one-line comment */
bool str, chr; /* in string/char literal */
blc=olc=str=chr=false;
char c,pc='\0';
while ( is.get(c) ) {
// escape
if ( c == '\\' ) {
if ( !olc && !blc ) {
if ( pc == '/' )
os.put('/');
os.put(c);
}
is.get(c);
if ( !olc && !blc )
os.put(c);
}
// end of one-line comment
else if ( olc && (c == '\n' || c == '\r') ) {
olc = false;
os.put(c);
pc = '\0';
continue;
}
// end of block comment
else if ( blc && pc == '*' && c == '/' ) {
blc = false;
pc = '\0';
continue;
}
// start of one-line comment
else if ( pc == '/' && c == '/' && !str && !chr && !blc ) {
olc = true;
pc = '\0';
continue;
}
// start of block comment
else if ( pc == '/' && c == '*' && !str && !chr && !olc ) {
blc = true;
pc = '\0';
}
// start/end of char literal
else if ( !olc && !blc && c == '\'' ) {
chr = !chr;
if ( pc == '/' )
os.put('/');
os.put(c);
}
// start/end of string literal
else if ( !olc && !blc && c == '\"' ) {
str = !str;
if ( pc == '/' )
os.put('/');
os.put(c);
}
else {
if ( pc == '/' && !olc && !blc )
os.put('/');
if ( c != '/' && !olc && !blc )
os.put(c);
}
pc = c;
}
}
namespace {
const char* test = "//\
" "/*" "hoge" "*/"
/* / * /* // */ "hige";
}
int main(int c, char** v)
{
(void)test;
if ( c < 2 ) {
std::cout << "usage: " << v[0] << " <C++ source file>\n";
return 0;
}
std::ifstream ifs(v[1]);
if ( !ifs ) {
std::cerr << "failed to open " << v[1] << "\n";
return 1;
}
decomment(std::cout, ifs);
return 0;
}
|
CPANモジュール PPI を利用して。 # SYNOPSISにまんまコメント削除の例が載ってたし
see: PPI
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 | use strict;
use warnings;
use PPI;
=head1 NAME
decomment - strip comments/pods from code
=head1 SYNOPSIS
decomment.pl <some.pl>
=head1 SEE ALSO
L<http://ja.doukaku.org/185/>
PPI L<http://search.cpan.org/~adamk/PPI-1.203/lib/PPI.pm>
=cut
if ( !$ARGV[0] ) {
print "usage: $0 <some.pl>\n";
exit 0;
}
# test data
my $testdata = "string with # :)"; # this is a comment;
# use PPI to strip comment from code
my $doc = PPI::Document->new($ARGV[0]);
$doc->prune(q/PPI::Token::Pod/);
$doc->prune(q/PPI::Token::Comment/);
print $doc->content;
__END__
this section is not a comment.
|
やっつけです
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 | #include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
FILE *f;
char c;
int flg = 0;
if(argc != 2)
exit(EXIT_FAILURE);
f = fopen(argv[1], "r");
while((c = fgetc(f)) != EOF) {
if((flg == 0) && (c == '/')) {
flg = 1;
continue;
} else if((flg == 1) && (c == '/')) {
flg = 2;
} else if((flg == 1) && (c == '*')) {
flg = 3;
} else if((flg == 1) && (c != '/') && (c != '*')) {
putchar('/');
flg = 0;
} else if((flg == 3) && (c == '*')) {
flg = 4;
} else if((flg == 4) && (c == '/')) {
flg = 5;
}
if(flg == 0) {
putchar(c);
}
if((flg == 2) && (c == '\n')){
flg = 0;
}
if(flg == 5) {
flg = 0;
}
}
exit(EXIT_SUCCESS);
}
|
ストリームを使っているだけで実質Cですね…。
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 | #include <iostream>
static void decomment(std::istream& in, std::ostream& out)
{
in.unsetf(std::ios::skipws);
char c;
char prev = 0;
while(in >> c)
{
if(c == '/')
{
prev = c;
in >> c;
if(c == '*')
{
do
{
while((in >> c) && (c != '*'))
{
if(c == '\n')
{
out << c;
}
}
} while((in >> c) && (c != '/'));
c = ' ';
}
else if(c == '/')
{
while((in >> c) && (c != '\n'))
; // NOP
}
else
{
out << prev;
}
}
else if((c == '"') && (prev != '\\') && (prev != '\''))
{
do
{
out << c;
if(c == '\\')
{
in >> c;
out << c;
}
} while((in >> c) && (c != '"'));
}
out << c;
prev = c;
}
}
int main(int, char*[])
{
decomment(std::cin, std::cout);
return 0;
}
|
comment-kill がやるようです。
1 2 3 4 5 6 7 | (defun decomment (buffer)
"バッファ内のコメント文を削除します"
(interactive "bdecomment ")
(with-current-buffer buffer
(save-excursion
(goto-char (point-min))
(comment-kill (point-max)))))
|
α置換の時に使ったパーサーがコメントを読み落としてしまうことを利用しました。もっと単純に文字列のパースでもできるはずですが、既存のソースに手を加えればできるということで…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | module Main where
import Language.Haskell.Syntax
import Language.Haskell.Parser
import Language.Haskell.Pretty
import Data.Generics
pp :: ParseResult HsModule -> String
pp (ParseOk hsm) = prettyPrint hsm
pp _ = "parse failed"
main :: IO ()
main
= do mod <- getContents
putStr $ pp $ parseModule mod
|
初投稿 泥です。 初めてre使った
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import re, sys
try :
f = open(sys.argv[1], "r")
raw_str = f.read()
f.close()
except :
print "file read error"
sharpe = re.compile(".*#.*")
s_quote = re.compile("'''")
d_quote = re.compile('"""')
de_sharpe_str = ""
tmp = raw_str.split("\n")
for i in tmp:
de_sharpe_str += sharpe.split(i)[0] + "\n"
x = [s_quote.split(de_sharpe_str)[x]for x in range(0, len(s_quote.split(de_sharpe_str)), 2)]
y = [d_quote.split(de_sharpe_str)[x]for x in range(0, len(x), 2)]
print "\n".join(y)
|
これはパーサーの実装に依存したハックですね…
writeだと,#0=(1 . #0#)で終わらないのでwirte/ssを使いました.
1 | (port-for-each write/ss read)
|
#6573のでは,トップレベルに直接変数が書いてあった時に,くっ付いてしまいますね.
1 | (port-for-each (lambda (s) (write/ss s) (newline)) read)
|
相互再帰風に書いてみました
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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | #include <stdio.h>
typedef void* (*filter)(int c, FILE* out);
void drive(filter f, FILE* in, FILE* out)
{
int c;
do {
c = fgetc(in);
if (c == EOF)
break;
} while ((f = f(c, out)));
}
#define CALL(func) \
do { return func; } while(0)
#define FINISH() \
do { return NULL; } while(0)
void* normal_code(int, FILE*);
void* next_of_slash_in_normal_code(int, FILE*);
void* string(int, FILE*);
void* next_of_backslash_in_string(int, FILE*);
void* single_quote(int, FILE*);
void* next_of_backslash_in_single_quote(int, FILE*);
void* comment(int, FILE*);
void* next_of_star_in_comment(int, FILE*);
void* oneline_comment(int, FILE*);
void* normal_code(int c, FILE* out)
{
switch (c) {
case '/':
CALL(next_of_slash_in_normal_code);
case '"':
fputc(c, out);
CALL(string);
case '\'':
fputc(c, out);
CALL(single_quote);
default:
fputc(c, out);
CALL(normal_code);
}
}
void* next_of_slash_in_normal_code(int c, FILE* out)
{
switch (c) {
case '*':
CALL(comment);
case '/':
CALL(oneline_comment);
default:
fputc('/', out);
fputc(c, out);
CALL(normal_code);
}
}
void* string(int c, FILE* out)
{
fputc(c, out);
switch (c) {
case '\\':
CALL(next_of_backslash_in_string);
case '"':
CALL(normal_code);
default:
CALL(string);
}
}
void* next_of_backslash_in_string(int c, FILE* out)
{
fputc(c, out);
CALL(string);
}
void* single_quote(int c, FILE* out)
{
fputc(c, out);
switch (c) {
case '\\':
CALL(next_of_backslash_in_single_quote);
case '\'':
CALL(normal_code);
default:
CALL(single_quote);
}
}
void* next_of_backslash_in_single_quote(int c, FILE* out)
{
fputc(c, out);
CALL(single_quote);
}
void* comment(int c, FILE* out)
{
if (c == '*')
CALL(next_of_star_in_comment);
else
CALL(comment);
}
void* next_of_star_in_comment(int c, FILE* out)
{
if (c == '/')
CALL(normal_code);
else
CALL(comment);
}
void* oneline_comment(int c, FILE* out)
{
if (c == '\n')
CALL(normal_code);
else
CALL(oneline_comment);
}
void decomment(FILE* in, FILE* out)
{
drive(normal_code, in, out);
}
int main(int argc, char** argv)
{
decomment(stdin, stdout);
return 0;
}
|
おもいっきりベタな実装してみました。もしかすると抜けている部分があるかもしれません…。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | decomment :: String -> String
decomment s = decommentNormal s
where
decommentNormal [] = []
decommentNormal ('\'':'"':'\'':cs) = '\'':'"':'\'':(decommentNormal cs)
decommentNormal ('\'':'\\':'"':'\'':cs) = '\'':'\\':'"':'\'':(decommentNormal cs)
decommentNormal ('"':cs) = '"':(decommentQuote cs)
decommentNormal ('-':'-':cs) = decommentCommentLine cs
decommentNormal ('{':'-':cs) = decommentCommentBlock 0 cs
decommentNormal (c:cs) = c:(decommentNormal cs)
decommentQuote ('"':cs) = '"':(decommentNormal cs)
decommentQuote ('\\':'"':cs) = '\\':'"':(decommentQuote cs)
decommentQuote (c:cs) = c:(decommentQuote cs)
decommentCommentLine ('\n':cs) = '\n':(decommentNormal cs)
decommentCommentLine (_:cs) = decommentCommentLine cs
decommentCommentBlock 0 ('-':'}':cs) = '\n':(decommentNormal cs)
decommentCommentBlock n ('-':'}':cs) = decommentCommentBlock (n-1) cs
decommentCommentBlock n ('{':'-':cs) = decommentCommentBlock (n+1) cs
decommentCommentBlock n (c:cs) = decommentCommentBlock n cs
main = getContents >>= putStrLn.decomment
|
ちょっと長いけど,Haskell, C, C++ 対応のつもり,
CommentStyleクラスとQuoteStyleクラスを使って,いろいろな言語に対応できるように工夫してみた.
- commentLeadings メソッドは一行コメントの開始マーク(複数可)文字列を返すメソッド
- commentOpenings メソッドはブロックコメントの開始マーク(複数可)文字列を返すメソッド
- commentClosing メソッドは与えられたブロックコメントの開始マークに対応する修了マークを返すメソッド
- commentNestable はブロックコメントがネスト可能かどうかを返すメソッド
など.
- 文字列リテラル
- ブロックコメントのネスト
に対応する.厳密にやるには,その言語のパーザを読んで結果の構文木データを,プリティプリンタ(自作することになる)に食わせるのかな.めんどうだけど...
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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | {-# LANGUAGE EmptyDataDecls #-}
module Main (main) where
import Control.Arrow
import Data.Char
import Data.List
import Data.Maybe
import System.Environment
main :: IO ()
main = interact . genDecomment . listToMaybe . map (map toLower) =<< getArgs
genDecomment :: Maybe String -> String -> String
genDecomment (Just "c") = decomment cstyle
genDecomment (Just "c++") = decomment cppstyle
genDecomment _ = decomment hstyle
class CommentStyle c where
commentLeadings :: c -> [String]
commentOpenings :: c -> [String]
commentClosing :: c -> String -> String
commentNestable :: c -> Bool
class QuoteStyle q where
quoteOpenings :: q -> [Char]
quoteClosing :: q -> Char -> Char
quoteEscape :: q -> Char
splitWithPrefix :: Eq a => [a] -> [a] -> Maybe ([a],[a])
splitWithPrefix [] xs = Just ([],xs)
splitWithPrefix (p:ps) xxs@(x:xs)
| p == x = splitWithPrefix ps xs >>= return . ((x:) *** id)
| otherwise = Nothing
splitQuoted :: Eq a => a -> a -> [a] -> ([a], [a])
splitQuoted esc qm [] = ([],[])
splitQuoted esc qm (c:cs)
| c == qm = ([],cs)
| c == esc = case cs of
[] -> ([c],[])
c':cs' -> ((c:).(c':) *** id) $ splitQuoted esc qm cs'
| otherwise = ((c:) *** id) $ splitQuoted esc qm cs
decomment :: (CommentStyle s, QuoteStyle s) => s -> String -> String
decomment s "" = ""
decomment s ccs@(c:cs) = case mapMaybe (flip splitWithPrefix ccs) $ commentLeadings s of
(_,xs):_ -> decomment s $ snd $ break ('\n'==) xs
[] -> case mapMaybe (flip splitWithPrefix ccs) $ commentOpenings s of
(p,xs):_ -> decommentC s [p] xs
[] -> if elem c (quoteOpenings s) then c:decommentQ s c cs
else c |




nobsun
#6534()
Rating-1/5=-0.20
[ reply ]