/ * & * /를 포함하여 / *… * /에 속하는 모든 문자를 어떻게 삭제합니까?


12

나는 sed와 awk를 시도했지만 문자가 이미 분리 문자로 명령에있는 "/"를 포함하므로 작동하지 않습니다.

어떻게하면되는지 알려주세요.

아래는 샘플 예제입니다. 주석 처리 된 섹션을 제거하려고합니다. /*.....*/

/*This is to print the output
data*/
proc print data=sashelp.cars;
run;
/*Creating dataset*/
data abc;
set xyz;
run;

-bash-4.1 $ sed 's, / *. ** / ,, g'test.sas 아래는 내가 얻은 출력이며 첫 번째 주석은 여전히 ​​존재합니다. / * 출력 데이터를 인쇄합니다 * / proc print data = sashelp.cars; 운영; 데이터 abc; 세트 xyz; 운영;
Sharique Alam

1
편집 해 주셔서 감사합니다. 원하는 출력도 포함하면 더 좋습니다. 또한 의견이 아닌 질문에 시도한 것과 실패한 방법을 포함하십시오.
terdon

2
주석 또는 주석 구분자가 포함 된 문자열 리터럴은 어떻게됩니까? (예 INSERT INTO string_table VALUES('/*'), ('*/'), ('/**/');)
zwol

1
관련 (미안 나는 저항 할 수없는!) : codegolf.stackexchange.com/questions/48326/...
ilkkachu

다른 솔루션으로 게시물을 업데이트했습니다. 지금 귀하에게 적합한 지 다시 확인하십시오.
Luciano Andress Martini 2018

답변:


22

나는 쉬운 해결책을 찾았다 고 생각한다!

cpp -P yourcommentedfile.txt 

일부 업데이트 :

사용자 ilkachu의 인용문 (사용자 의견의 원본) :

gcc에 대한 옵션으로 약간 연주했습니다. -fpreprocessed 는 대부분의 지시문 및 매크로 확장을 비활성화합니다 (#define 및 #undef는 분명히 제외). -dD 를 추가하면 정의도 그대로 남습니다 . 및 표준 = C89 새로운 스타일의 // 주석을 무시하는 데 사용할 수 있습니다. 그들과 함께도 cpp는 주석을 제거하는 대신 공백으로 바꾸고 공백과 빈 줄을 축소합니다.

그러나 나는 그것이 여전히 합리적이고 대부분의 경우에 쉬운 해결책이라고 생각합니다. 매크로 확장 및 기타 것들을 비활성화하면 좋은 결과를 얻을 것이라고 생각합니다. ... 그리고 훨씬 더 ...


1
C 전처리기를 사용하는 것이 가장 강력한 솔루션 일 것입니다. 전처리 기가 C 주석의 가장 강력한 파서 일 가능성이 있기 때문입니다. 영리한.
grochmal

14
그러나 cpp주석을 제거하는 것 (프로세스 #include, 내장 매크로를 포함하여 매크로 확장 ...) 보다 훨씬 더 많은 작업을 수행 할 것입니다.
Stéphane Chazelas

3
@LucianoAndressMartini, 아니요, tail -n +7처음 7 줄만 제거하므로 #include처리 또는 매크로 확장을 막을 수 없습니다 . echo __LINE__ | cpp예를 들어 보십시오 . 또는echo '#include /dev/zero' | cpp
Stéphane Chazelas

2
이렇게하면 -P모드 를 사용하고 싶을 것입니다 . (이것은 사용 필요성을 제거 할 수 있습니다 tail.)
zwol

3
gcc : 옵션을 사용하여 약간의 연주를했습니다. -fpreprocessed대부분의 지시문과 매크로 확장을 비활성화합니다 (제외 #define하고 #undef명백하게). 추가 -dD하면 정의도 남습니다. 그리고 std=c89새로운 스타일 무시하는 데 사용할 수있는 //의견을. 그들과 함께도 cpp주석을 제거하는 대신 공백으로 바꾸고 공백과 빈 줄을 접습니다.
ilkkachu

10

나는 우리가 다듬을 수 있는 이것을 생각해 냈습니다 .

perl -0777 -pe '
  BEGIN{
    $bs=qr{(?:\\|\?\?/)};
    $lc=qr{(?:$bs\n|$bs\r\n?)}
  }
  s{
    /$lc*\*.*?\*$lc*/
    | /$lc*/(?:$lc|[^\r\n])*
    | (
         "(?:$bs$lc*.|.)*?"
       | '\''$lc*(?:$bs$lc*(?:\?\?.|.))?(?:\?\?.|.)*?'\''
       | \?\?'\''
       | .[^'\''"/?]*
      )
  }{$1 eq "" ? " " : "$1"}exsg'

몇 가지 더 코너 케이스를 처리합니다.

당신이 경우주의 제거 코멘트를, 당신은 코드의 의미를 변화시킬 수는 ( 1-/* comment */-1같은 구문 분석 1 - -1하는 동안 1--1(당신은 코멘트를 제거한 경우 당신이 얻을 거라고하는)이 당신에게 오류를 줄 것이다). 주석을 완전히 제거하는 대신 주석을 공백 문자 (여기에서하는 것처럼)로 바꾸는 것이 좋습니다.

위의 몇 가지 경우를 포함하려고하는이 유효한 ANSI C 코드에서 올바르게 작동해야합니다.

#include <stdio.h>
int main ()
{
  printf ( "% d % s % c % c % c % c % c % s % s % d \ n",
  1-/ * 주석 * /-1,
  / \
* 의견 * /
  "/ * 주석이 아님 * /",
  / * 여러 줄
  의견 * /
  ' "'/ * comment * /, '"',
  '\' ',' " '/ * 주석 * /,
  '\
\
" ', / * 코멘트 * /
  "\\
"/ * 주석이 아님 * /",
  "?? /"/ * 코멘트가 아님 * / ",
  '??' '+' " '/ *"주석 "* /);
  리턴 0;
}

이 출력을 제공합니다 :

#include <stdio.h>
int main ()
{
  printf ( "% d % s % c % c % c % c % c % s % s % d \ n",
  1 ~ 1,

  "/ * 주석이 아님 * /",

  ' "', '"',
  '\' ',' " ',
  '\
\
" ',  
  "\\
"/ * 주석이 아님 * /",
  "?? /"/ * 코멘트가 아님 * / ",
  '??' '+' " ');
  리턴 0;
}

컴파일 및 실행시 모두 동일한 출력을 인쇄합니다.

gcc -ansi -E프리 프로세서가 수행하는 작업을보기 위해 출력과 비교할 수 있습니다 . 그 코드는하지만, 또한 유효 C99 또는 C11 코드 gcctrigraph를 기본적으로 지원하지 않습니다 그렇게하지 않습니다와 일 gcc이 같은 표준을 지정하지 않은 경우 gcc -std=c99gcc -std=c11또는 추가 -trigraphs) 옵션을 선택합니다.

이 C99 / C11 (비 ANSI / C90) 코드에서도 작동합니다.

// 댓글
/ \
/ 댓글
// 여러 줄 \
논평
"// 코멘트가 아님"

( gcc -E/ gcc -std=c99 -E/ 와 비교 gcc -std=c11 -E)

ANSI C는 // form이 의견을 지지하지 않았습니다 . //그렇지 않으면 ANSI C에서는 유효하지 않으므로 표시되지 않습니다. 하나 인위적인 사건은 어디에서 //(언급 한 바와 같이 진정으로 ANSI C에 나타날 수 있다 , 당신은 토론 흥미의 나머지 부분을 찾을 수 있음) 할 때입니다 캐릭터 라인 화 연산자를 사용 중입니다.

유효한 ANSI C 코드입니다.

#define s(x) #x
s(//not a comment)

그리고 2004 년에 토론 할 당시에 gcc -ansi -E실제로 그것을 확장했습니다 "//not a comment". 그러나 오늘날 gcc-5.4에는 오류가 발생하므로 이러한 종류의 구문을 사용하여 많은 C 코드를 찾을 수있을 것입니다.

GNU sed와 동등한 것은 다음과 같습니다.

lc='([\\%]\n|[\\%]\r\n?)'
sed -zE "
  s/_/_u/g;s/!/_b/g;s/</_l/g;s/>/_r/g;s/:/_c/g;s/;/_s/g;s/@/_a/g;s/%/_p/g;
  s@\?\?/@%@g;s@/$lc*\*@:&@g;s@\*$lc*/@;&@g
  s:/$lc*/:@&:g;s/\?\?'/!/g
  s#:/$lc*\*[^;]*;\*$lc*/|@/$lc*/$lc*|(\"([\\\\%]$lc*.|[^\\\\%\"])*\"|'$lc*([\\\\%]$lc*.)?[^\\\\%']*'|[^'\"@;:]+)#<\5>#g
  s/<>/ /g;s/!/??'/g;s@%@??/@g;s/[<>@:;]//g
  s/_p/%/g;s/_a/@/g;s/_s/;/g;s/_c/:/g;s/_r/>/g;s/_l/</g;s/_b/!/g;s/_u/_/g"

당신의 GNU이 경우 sed너무 오래 지원 -E또는 -z당신이 첫 번째 라인을 교체 할 수 있습니다 :

sed -r ":1;\$!{N;b1}

펄 솔루션은 멀티 라인에 문제가 있습니다 :이 출력으로 테스트 => echo -e "BEGIN / * comment * / COMMAND / * com \ nment * / END"
بارپابابا

@Babby, 저에게 효과적입니다. 테스트 줄에 여러 줄 주석과 결과 출력을 추가했습니다.
Stéphane Chazelas

요즘 비교할 가장 좋은 것은 gcc -std=c11 -E -P(의 -ansi또 다른 이름 일 것입니다 -std=c90).
zwol

@zwol, 모든 C / C ++ 표준 (c90, c11 또는 기타)을 위해 작성된 코드를 처리 할 수 ​​있어야합니다. 엄밀히 말하면 불가능합니다 (두 번째로 고안된 예 참조). 코드는 여전히 (같은 C90 구조를 처리하려고 ??'), 따라서 우리가 비교 cpp -ansiC99은 / C11 ... 하나 (같은 그와에 대한 // xxx) 따라서 우리가 비교 cpp(또는 cpp -std=c11...)
스테판 Chazelas가

@zwol, 나는 약간을 명확히하기 위해 테스트 사례를 나누었습니다. trigraphs가 여전히 C11에있는 것처럼 보이므로 두 번째 테스트 사례는 표준 C가 아닙니다.
Stéphane Chazelas

6

sed:

최신 정보

/\/\*/ {
    /\*\// {
        s/\/\*.*\*\///g;
        b next
    };

    :loop;
    /\*\//! {
        N;
        b loop
    };
    /\*\// {
        s/\/\*.*\*\//\n/g
    }
    :next
}

가능한 모든 지원 (멀티 라인 주석, [또는 and] 이후의 데이터,);

 e1/*comment*/
-------------------
e1/*comment*/e2
-------------------
/*comment*/e2
-------------------
e1/*com
ment*/
-------------------
e1/*com
ment*/e2
-------------------
/*com
ment*/e2
-------------------
e1/*com
1
2
ment*/
-------------------
e1/*com
1
2
ment*/e2
-------------------
/*com
1
2
ment*/e2
-------------------
운영:
$ sed -f command.sed FILENAME

e1
-------------------
e1e2
-------------------
e2
-------------------
e1

-------------------
e1
e2
-------------------

e2
-------------------
e1

-------------------
e1
e2
-------------------

e2
-------------------

데이터 다음에 시작하는 주석에는 작동하지 않습니다.proc print data 2nd /*another comment is here*/
mazs

@mazs 업데이트, 확인
بارپابابا

이것은 문자열 리터럴 내부의 주석을 처리하지 않으며, SQL의 기능에 따라 실제로 중요 할 수 있습니다.
zwol

4
 $ cat file | perl -pe 'BEGIN{$/=undef}s!/\*.+?\*/!!sg'

 proc print data=sashelp.cars;
 run;

 data abc;
 set xyz;
 run;

빈 줄이 있다면 제거하십시오 :

 $ cat file | perl -pe 'BEGIN{$/=undef}s!/\*.+?\*/\n?!!sg'

편집-Stephane의 짧은 버전 :

 $ cat file | perl -0777 -pe 's!/\*.*?\*/!!sg'

글쎄, 나는 terdon에 동의합니다 : 예상 출력을 보자.
Hans Schou

BTW : "/ * foo * / run; / * bar * /"?를 포함하는 단일 행은 어떻게됩니까? 그냥 "실행"해야합니까? ?
Hans Schou

큰! 그런 다음 내 솔루션이 작동합니다. 참고 : ". +?"
Hans Schou

2
참조 -0777할 수있는 짧은 방법으로BEGIN{$/=undef}
스테판 Chazelas가

1
아마도 if .*?대신 유효한 주석이기도합니다. .+?/**/
ilkkachu

2

스크립트없이 SED 명령을 사용한 솔루션

여기 있어요:

sed 's/\*\//\n&/g' test | sed '/\/\*/,/\*\//d'

NB 설치하지 않으면 OS X에서 작동하지 않습니다 gnu-sed. 그러나 Linux Distros에서는 작동합니다.


1
-i출력을 새 파일로 리디렉션하는 대신 옵션을 사용 하여 파일을 내부 편집 할 수 있습니다 . 또는 훨씬 더 안전한 -i.bak백업 파일
Rahul

1
모든 경우에도 작동하지는 않습니다. 같은 줄에 주석을 달고 무슨 일이 일어나는지 살펴보십시오 ... 예제 set xy \; / * test * / 펄도 너무 쉽게 해결해야한다고 생각합니다.
Luciano Andress Martini

@Rahul 정확하게 언급 해 주셔서 감사합니다. 나는 그것을 더 단순하게 유지하고 싶었다.
FarazX

같은 줄에서 주석을 처리하지 않는다고 말하면 매우 유감입니다.
Luciano Andress Martini

@LucianoAndressMartini 이제 그렇습니다!
FarazX

1

sed한 번에 한 줄씩 작동하지만 입력의 일부 주석은 여러 줄에 걸쳐 있습니다. 당으로 /unix//a/152389/90751 먼저 사용할 수있는 tr몇 가지 다른 문자로 줄 바꿈을 켭니다. 그런 다음 sed입력을 한 줄로 처리하고 tr다시 사용 하여 줄 바꿈을 복원 할 수 있습니다 .

tr '\n' '\0' | sed ... | tr '\0' \n'

null 바이트를 사용했지만 입력 파일에 나타나지 않는 문자를 선택할 수 있습니다.

*정규 표현식에서 특별한 의미가 있으므로 \*리터럴과 일치하도록 탈출해야합니다 *.

.*욕심많으며 more */및을 포함하여 가장 긴 텍스트와 일치합니다 /*. 즉, 첫 번째 주석, 마지막 주석 및 그 사이의 모든 것을 의미합니다. 이를 제한하려면 .*더 엄격한 패턴으로 바꾸십시오 . 주석에는 "*"가 아닌 모든 항목과 "*"가 아닌 다른 항목이 포함될 수 있습니다. 여러 번의 실행 *도 고려해야합니다.

tr '\n' '\0' | sed -e 's,/\*\([^*]\|\*\+[^*/]\)*\*\+/,,g' | tr '\0' '\n'

여러 줄 주석에서 줄 바꿈을 제거합니다.

data1 /* multiline
comment */ data2

될 것입니다

data1  data2

이것이 원하는 것이 아니라면 줄 sed바꿈 중 하나를 유지하도록 지시 할 수 있습니다. 이는 일치 할 수있는 줄 바꿈 대체 문자를 선택하는 것을 의미합니다.

tr '\n' '\f' | sed -e 's,/\*\(\(\f\)\|[^*]\|\*\+[^*/]\)*\*\+/,\2,g' | tr '\f' '\n'

특별한 특성 \f과 일치하지 않는 역 참조를 사용한다고해서 모든 sed구현 에서 의도 한대로 작동하는 것은 아닙니다 . (GNU sed 4.07 및 4.2.2에서 작동 함을 확인했습니다.)


어떻게 작동하는지 mne에 알려주십시오. 아래와 같이 시도했습니다. tr '\ n' '\ 0'| sed -e 's, / * ([^ *] \ | * \ + [^ * /]) ** \ + / ,, g'test.sas | tr '\ 0' '\ n'이고 다음과 같이 표시됩니다. / * 출력 데이터를 인쇄합니다 * / data abcdf; cfgtr을 설정하십시오. 운영; proc print data = sashelp.cars; 운영; 데이터 abc; 세트 xyz; 운영;
Sharique Alam

@ShariqueAlam test.sas파이프 라인의 중간에 넣었 으므로 sed직접 읽습니다 tr. 첫 번째 는 효과가 없습니다. 당신은 사용해야합니다cat test.sas | tr ...
JigglyNaga

0

한 줄 sed를 사용하여 주석을 제거하십시오.

sed '/\/\*/d;/\*\//d' file

proc print data=sashelp.cars;
run;
data abc;
set xyz;
run;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.