[완료] C++ 에서 텍스트 파일을 읽을때 주석 제거하기

jinserk의 이미지

어떤 config.txt 가 다음과 같을때

# comment
 
1 2 3
4 #5 6

1,2,3,4 만 읽고 싶습니다.

이를 위해서 다음과 같이 주석을 제거하는 코드를 작성해 봤습니다.

  34     std::ifstream       ifs(syscfg_file.c_str());
  35     if (ifs.fail())
  36         error("file does not exist");
  37 
  38     char tmp[256];
  39     std::istringstream   iss;
  40     while (!ifs.eof()) {
  41         ifs.getline(tmp, 256);
  42         std::cout << tmp << std::endl;
  43         iss.str(tmp);
  44         std::cout << iss.str() << std::endl;
  45         iss.getline(tmp, 256, '#');
  46         std::cout << tmp << std::endl;

그런데, 46번 행에서 # 앞부분만 나올것으로 기대했건만,
아무것도 나오질 않네요.

질문 1. # 이후를 무시한 주석 제거 알고리듬을 C++ 로 어떻게 구현하면 될까요?

질문 2. 공백과 \n 으로만 이루어진 행은 어떻게 제거하면 될까요?

semmal의 이미지

그냥 고민안하고 한다면 getline해서 '#'으로 split해서 뒷부분은 버리면 됩니다.

화이트스페이스는 trim 합니다.

그런데, 이 목적만이 아니고 interpreter처럼 만들려고 하면, 그냥 lexer를 손으로 만듭니다.

lexer를 손으로 만드는게 귀찮거나, 수정사항이 많다면 lex를 씁니다.

따로 파일놔두고 관리하기 싫어서 lex가 별로라면, spirit을 씁니다.
------------------------------
How many legs does a dog have?

------------------------------
How many legs does a dog have?

jinserk의 이미지

getline 에 delim 을 # 으로 쓴다면
주석이 없는 행을 읽을때 그 다음줄까지 읽어버리지 않는지요? (즉, \n 에서 분리하지 않는게 아닌가..)

게다가 white space 만 있는 행도 하나의 line 으로 읽을텐데
그 경우는 변수들을 읽어들이다 에러가 날 수도 있겠구요.

지금 하려는 것은 하나의 행에 정해진 수의 값들이 있다고 가정하고
그만큼 읽어들일 생각이라서..

Leo.

winner의 이미지

제 생각에는 semmal님의 방식이 깔끔해 보입니다.
istringstream을 쓰시는 걸로 봐서는 C++ 표준 library에 익숙하실 것 같은데 조금만 더 고민하시면 해결하실 수 있을 것 같네요.
Andrew Koenig의 Accelerated C++에서 URL 인식이 들어있던 것으로 기억합니다. 참고하시면 도움이 되실 것 같습니다.

jinserk의 이미지

1. 읽으려는 text 파일에는 N 열의 상수가 있습니다. 상수는 int, float, char 가 혼합되어 있습니다.
2. # 으로 시작하거나 한 행에서 # 이후는 comment 로 무시합니다.
3. whitespace 만으로 이루어진 행 역시 무시합니다.

예제: N = 3

# this comment            <- 무시
                          <- 공백문자 + \n 역시 무시
1 10.5 c                  <- 3개의 상수. ok
2 8.1  d  # comment       <- 3개의 상수 + comment. ok
   3 1.4 e               <- 행 앞에 임의의 공백문자. ok
   4 #3.4 f                  <- 1개의 상수. error

윗분들께서 말씀해주신대로 다음과 같이 코딩을 해봤습니다.

std::ifstream ifs(filename);
std::string line;
std::istringstream iss;
 
int a;
float b;
char c;
 
while (getline(ifs, line)) {
    std::string::size_type pos = line.find_first_of('#');
    iss.str(line.substr(0, pos));
 
    iss >> a >> b >> c;
 
    std::cout << a << ' ' << b << ' ' << c << std::endl;

그리고 나서 아래와 같은 text 파일로 테스트를 해봤습니다.

# test
#
 
1 1.1 a
2 2.2 b # comment
    3 3.3 c
    4 #4.4 d

결과입니다.

0 5.67388e+036 
 
0 5.67388e+036
 
0 5.67388e+036
1 1.1 a
0 5.67388e+036
2 2.2 b
0 5.67388e+036
   3 3.3 c
0 5.67388e+036
   4
0 5.67388e+036

우선 a, b, c 에 제대로 값이 들어가지 않구요,
주석행도 하나의 행으로 읽어 버리고
그리고 공백문자 제거도 안되는 듯 합니다.

다시금 조언을 구합니다.

감사합니다.

Leo.

winner의 이미지

http://www.cplusplus.com/reference/iostream/istringstream/str/

꼼꼼히 읽어보시고, 문제점은 약간만 생각해보시면 될겁니다.

jinserk의 이미지

코드를 아래와 같이 바꾸니까 일단 값을 읽는건 되네요.

std::ifstream ifs(filename);
std::string line;
 
int a;
float b;
char c;
 
while (getline(ifs, line)) {
    std::string::size_type pos = line.find_first_of('#');
    std::istringstream iss(line.substr(0, pos));
 
    iss >> a >> b >> c;
    std::cout << a << ' ' << b << ' ' << c << std::endl;

iss 를 미리 생성하고 str() 로 스트링만 업데이트 해서는 buffer 와 sync 가 안되는
모양입니다. 그래서 while 내부에서 iss 를 생성하는걸로 바꾸니까 일단 iss 에서
값을 읽는 건 동작합니다.

문제는.. 위에 언급한대로 주석행이나 데이터 열이 N 이 안되는 행들은
에러 처리가 되지 않아서 역시 쓰레기값이 들어간다는 점입니다.

iss 가 비어 있더라도 >> operator 는 에러를 내질 않네요. :(

Leo.

jinserk의 이미지

std::ifstream ifs(filename);
std::string line;
std::istringstream iss;
 
int a;
float b;
char c;
 
while (getline(ifs, line)) {
    std::string::size_type pos = line.find_first_of('#');
    iss.str(line.substr(0, pos));
    iss.clear();
 
    iss >> a;
    if (iss.fail()) continue;  // 첫번째도 못읽으면 주석문으로 간주
 
    iss >> b >> c;
    if (iss.fail()) {          // 나머지를 못읽으면 N 보다 적은 값들이 있는걸로 간주
        std::cerr << "reading error" << std::endl;
        abort();
    }
 
    std::cout << a << ' ' << b << ' ' << c << std::endl;

iss.str() 은 fail / eof bit reset 을 안한다는게 키 였군요.
도움 주신 분들께 감사드립니다. :)

Leo.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.