C 소스 코드에서 문자열 제거 [닫기]
-
18-09-2019 - |
문제
C 소스 코드에서 문자열을 제거하는 프로그램을 알려줄 수 있는 사람이 있나요?예
#include <stdio.h>
static const char *place = "world";
char * multiline_str = "one \
two \
three\n";
int main(int argc, char *argv[])
{
printf("Hello %s\n", place);
printf("The previous line says \"Hello %s\"\n", place);
return 0;
}
된다
#include <stdio.h>
static const char *place = ;
char * multiline_str = ;
int main(int argc, char *argv[])
{
printf(, place);
printf(, place);
return 0;
}
내가 찾고 있는 것은 매우 유사한 프로그램이다. 스트립 cmt주석이 아닌 문자열을 제거하고 싶습니다.
내가 이미 개발 된 프로그램을 찾고 있고 편리한 정규 표현이 아니라 이미 개발 된 프로그램을 찾고있는 이유는 모든 코너 케이스 (문자열 내 인용문, 멀티 라인 문자열 등)를 고려하기 시작할 때 일반적으로 그보다 훨씬 더 복잡하기 시작하기 때문입니다. 먼저 나타납니다.그리고 RES가 달성 할 수있는 것에 제한이 있습니다.이 작업에는 불가능하다고 생각합니다.당신이 가지고 있다고 생각한다면 극도로 강력한 정규식을 자유롭게 제출하세요. 하지만 순진한 생각은 하지 마세요. sed 's/"[^"]*"//g'
제안처럼요.
(주석 내의 문자열(끝나지 않을 수도 있음)을 특별히 처리할 필요가 없습니다. 해당 문자열이 먼저 제거됩니다.)
줄 바꿈이 포함된 여러 줄 문자열에 대한 지원은 중요하지 않지만(적법한 C는 아님) 끝에 \로 끝나는 여러 줄에 걸쳐 있는 문자열은 지원되어야 합니다.
해결책
당신은 그것을 다운로드 할 수 있습니다 stripcmt에 대한 소스 코드 (.tar.gz -5kb). 사소하게 작으며 스트라이핑 문자열에 적응하기가 너무 어렵지 않아야합니다 ( GPL 아래에 출시되었습니다).
C 문자열에 대한 공식 어휘 언어 규칙을 조사 할 수도 있습니다. 나는 찾았다 이것 매우 빨리하지만 결정적이지 않을 수도 있습니다. 문자열을 다음과 같이 정의합니다.
stringcon ::= "{ch}", where ch denotes any printable ASCII character (as specified by isprint()) other than " (double quotes) and the newline character.
다른 팁
C(및 대부분의 다른 프로그래밍 언어)의 모든 토큰은 "일반"입니다.즉, 정규식으로 일치시킬 수 있습니다.
C 문자열에 대한 정규식:
"([^"\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))*"
정규식은 이해하기가 그리 어렵지 않습니다.기본적으로 문자열 리터럴은 다음을 묶는 큰따옴표 쌍입니다.
- 특수하지 않은(따옴표가 아닌/백슬래시/개행 문자) 문자
- 이스케이프는 백슬래시로 시작하고 다음 중 하나로 구성됩니다.
- 간단한 이스케이프 문자
- 1~3개의 8진수
- x 및 1개 이상의 16진수
이는 C89/C90 사양의 섹션 6.1.4 및 6.1.3.4를 기반으로 합니다.C99에 다른 것이 들어와도 이를 포착할 수는 없지만 해결하기 어렵지는 않습니다.
다음은 문자열 리터럴을 제거하여 C 소스 파일을 필터링하는 Python 스크립트입니다.
import re, sys
regex = re.compile(r'''"([^"\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))*"''')
for line in sys.stdin:
print regex.sub('', line.rstrip('\n'))
편집하다:
위의 내용을 게시한 후 모든 C 토큰이 일반 토큰인 것은 사실이지만 모든 것을 토큰화하지 않으면 문제가 발생할 수 있다는 생각이 들었습니다.특히, 다른 토큰이어야 하는 곳에 큰따옴표가 나타나면 우리는 정원 경로로 안내될 수 있습니다.주석은 이미 제거되었다고 말씀하셨는데, 우리가 정말로 걱정해야 할 유일한 것은 문자 리터럴입니다(그러나 제가 사용할 접근 방식은 주석 처리를 위해 쉽게 확장될 수 있습니다).다음은 문자 리터럴을 처리하는 보다 강력한 스크립트입니다.
import re, sys
str_re = r'''"([^"\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))*"'''
chr_re = r"""'([^'\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))'"""
regex = re.compile('|'.join([str_re, chr_re]))
def repl(m):
m = m.group(0)
if m.startswith("'"):
return m
else:
return ''
for line in sys.stdin:
print regex.sub(repl, line.rstrip('\n'))
본질적으로 우리는 문자열과 문자 리터럴 토큰을 찾은 다음 char 리터럴은 그대로 두고 문자열 리터럴을 제거합니다.char 리터럴 정규식은 문자열 리터럴 정규식과 매우 유사합니다.
루비에서 :
#!/usr/bin/ruby
f=open(ARGV[0],"r")
s=f.read
puts(s.gsub(/"(\\(.|\n)|[^\\"\n])*"/,""))
f.close
표준 출력에 인쇄합니다
pyparsing을 사용하는 파이썬에서 :
from pyparsing import dblQuotedString
source = open(filename).read()
dblQuotedString.setParseAction(lambda : "")
print dblQuotedString.transformString(source)
또한 stdout에 인쇄합니다.