Форум программистов, компьютерный форум CyberForum.ru

Удалить комментарии из строки - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 36, средняя оценка - 4.86
recovery101
1 / 1 / 0
Регистрация: 10.06.2011
Сообщений: 10
14.09.2011, 15:19     Удалить комментарии из строки #1
Привет. Вообщем такая задача: Прочитать из файла строку символов. Удалить из этой строки комментарии вида "/* ... */" (вложенные комментарии тоже удалить) . Новую строку не создавать. Вывести исходную и преобразованную строки.
Т.е. например: дана строка "gfsgsdsf /* jhasd */ asdas" и на выходе он выдает "gfsgsdsf asdas". Вот мой код
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
#include "stdafx.h"
#include <conio.h>
#include <stdio.h>
#include <iostream>
using namespace std;
void main ()
{
   setlocale (0,"Rus");
   int m = 0, n = 0;
   FILE * f;
   char buf[100];
   int length;
   f = fopen ("C:\\okfile.txt", "r");
   if (f == NULL) 
       perror ("Ошибка");
   else 
   {
     fgets (buf, 100 , f);
     puts (buf);
     fclose (f);
   }
   length = strlen(buf);
   for(int i = 0; i < length ; i++)
   {
       if ((buf[i] == '/') && (buf[i + 1] == '*'))
       {
          m = i;
       }
       if ((buf[i - 1] == '*') && (buf[i] == '/'))   
       {
          n = i;   
       }
       if ((m != 0) && (i == n))
       {
       int len = strlen(buf)-m;
       memmove(buf+m-1, buf+n+1, len);
       }
   }
   puts (buf);
   getch();
}
Но он не удаляет вложенные комментарии (комментарии в комментарии), т.е. надо чтобы при вводе строки "asdasd /* asd /*123*/ dsa*/ asdasd" выводил "asdasd asdasd".
Помогите пожалуйста исправить.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
soon
 Аватар для soon
2536 / 1301 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
14.09.2011, 15:59     Удалить комментарии из строки #2
Вам надо найти первое вхождение /* и последнее */, я правильно понял?
Если да, то вам надо вводить флаг(к примеру bool firstComment = 0) на нахождение первого комметария. И менять ветвление в 26 строчке, добавляя && !firstComment к условию, а к самому выполняемому действию firstComment = 1. Таким образом вы найдете первый комментарий в строке.
ps/ а в строке 30, при i == 0 не будет выхода за границу массива?
alkagolik
 Аватар для alkagolik
1510 / 616 / 79
Регистрация: 15.07.2011
Сообщений: 3,552
14.09.2011, 19:19     Удалить комментарии из строки #3
Цитата Сообщение от soon Посмотреть сообщение
а в строке 30, при i == 0 не будет выхода за границу массива?
будет конечно. надо учесть так же "//комментарий" и использовать конструкцию
C++
1
2
3
if()
else if()
else if()
soon
 Аватар для soon
2536 / 1301 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
14.09.2011, 20:10     Удалить комментарии из строки #4
будет конечно.
Своим вопросом я хотел натолкнуть самого ТС на ваше умозаключение. Ну да ладно.
Еще вдруг мысля посетила мой мозг - а в строке один комментарий? Если строка вида 123 /* 123 /* 123 */ 321 */ 123 /* йцук */ ен, то придется несколько раз проходить по строке, причем учитывать количество /*, и, пока их количество не будет равно */ не вырезать строку.
xdozorx
15 / 16 / 1
Регистрация: 13.12.2009
Сообщений: 138
Записей в блоге: 1
14.09.2011, 20:33     Удалить комментарии из строки #5
C++
1
2
3
4
5
6
7
8
  if ((buf[i] == '/') && (buf[i + 1] == '*'))
           {
                  m = i; break;
           }
           if ((buf[i - 1] == '*') && (buf[i] == '/'))   
           {
                  n = i;   break;
           }
так попробуй
soon
 Аватар для soon
2536 / 1301 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
14.09.2011, 20:59     Удалить комментарии из строки #6
Нужно будет 2 цикла. Как минимум. Для нахождения начальной и конечной позиции.
villu
202 / 202 / 4
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
14.09.2011, 23:02     Удалить комментарии из строки #7
1 цикл.
можно значительно упростить, как сейчас понял.
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
std::string remove_comment(const std::string &in) {
 
    enum state_t {
        state_clean = 0,
        state_start,
        state_rem,
        state_stop
    } state = state_clean;
 
    std::string clean;
    std::string out;
 
    std::string::const_iterator itr;
 
    size_t len = in.size();
    clean.reserve(len);
    out.reserve(len);
 
    std::string *cursor = &out;
    bool use_clean = false;
 
    for(itr = in.begin(); itr!=in.end(); ++itr) {
        switch( state ) {
        case state_clean:
            if(*itr == '/') state = state_start;
            else cursor->push_back(*itr);
            break;
        case state_start:
            if(*itr == '*') {
                if( use_clean ) {
                    use_clean = false;
                    cursor = &out;
                    out += clean;
                    clean.clear();
                }
                state = state_rem;
            } else {
                cursor->push_back('/');
                cursor->push_back(*itr);
                state = state_clean;
            }
            break;
        case state_rem:
            if(*itr == '*') state = state_stop;
            else if(*itr == '/') state = state_start;
            else if( use_clean ) cursor->push_back(*itr);
            break;
        case state_stop:
            if( *itr == '/' ) {
                use_clean = true;
                clean.clear();
                cursor = &clean;
            } else {
                cursor->push_back('*');
                cursor->push_back(*itr);
            }
            state = state_rem;
            break;
        }
    }
    if(!clean.empty()) out += (clean);
    return out;
}
C++
1
2
3
    std::string rem_str = "Kirje sinulle /* а это комент, да */ kyllГ¤! siina kaiiki; конец коммента */ siina kaikki.";
 
    cout << remove_comment(rem_str);
Bash
1
Kirje sinulle  siina kaikki.
может где есть какие глюки. не проверял сильно.
xAtom
 Аватар для xAtom
910 / 735 / 60
Регистрация: 09.12.2010
Сообщений: 1,346
Записей в блоге: 1
14.09.2011, 23:11     Удалить комментарии из строки #8
recovery101, вот накидал вариант, неограниченное удаление кол-во вложенных конструкций и т.п.
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
#include <stdio.h>
#include <string.h>
 
char*  str_erase(char*  str, const char* first, const char* last) {
    char* ptr;
    char* pa, *pb;
    int len;
 
    for(pa = NULL, ptr = str; ptr; ptr = strstr(ptr, first))  {
          if(ptr)
               pa = ptr;
          ptr += strlen(first);
    }  
    if(pa) {
        if((pb  = strstr(pa, last))) {
              pb += strlen(last);
              len  = pb - pa;
              memmove(str + (pa - str), str + (pb - str), strlen(str) - (pa - str));
              str_erase(str, first, last);
        }
    }
    return str;
}
 
 
int  main(void) {
 
      // тестирующия строка
      char str[] = "asdasd /* asd /*123*/ dsa*/ asdasd\n" \
                      "sample /* ops */HTML/*111*/ end.\n" \
                      "test /*1/*2/*fff*/2*/33*/fin/** /**/  **/:)";
 
      // вывод исходной строки
      printf("string src:\n%s\n\n", str);
    
      str_erase(str, "/*", "*/");
      printf("string dst:\n%s\n", str); // вывод обработанной
 
      getchar();
      return 0;
}
recovery101
1 / 1 / 0
Регистрация: 10.06.2011
Сообщений: 10
15.09.2011, 00:02  [ТС]     Удалить комментарии из строки #9
Цитата Сообщение от xAtom Посмотреть сообщение
recovery101, вот накидал вариант, неограниченное удаление кол-во вложенных конструкций и т.п.
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
#include <stdio.h>
#include <string.h>
 
char*  str_erase(char*  str, const char* first, const char* last) {
    char* ptr;
    char* pa, *pb;
    int len;
 
    for(pa = NULL, ptr = str; ptr; ptr = strstr(ptr, first))  {
          if(ptr)
               pa = ptr;
          ptr += strlen(first);
    }  
    if(pa) {
        if((pb  = strstr(pa, last))) {
              pb += strlen(last);
              len  = pb - pa;
              memmove(str + (pa - str), str + (pb - str), strlen(str) - (pa - str));
              str_erase(str, first, last);
        }
    }
    return str;
}
 
 
int  main(void) {
 
      // тестирующия строка
      char str[] = "asdasd /* asd /*123*/ dsa*/ asdasd\n" \
                      "sample /* ops */HTML/*111*/ end.\n" \
                      "test /*1/*2/*fff*/2*/33*/fin/** /**/  **/:)";
 
      // вывод исходной строки
      printf("string src:\n%s\n\n", str);
    
      str_erase(str, "/*", "*/");
      printf("string dst:\n%s\n", str); // вывод обработанной
 
      getchar();
      return 0;
}
Спасибо, вот только не совсем понял: это полноценный программный код или часть программы? Уж слишком сложные и незнакомые теги
talis
 Аватар для talis
789 / 541 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
15.09.2011, 01:12     Удалить комментарии из строки #10
recovery101, а что такое теги применительно к c++?

Cуть в том, что вам нужно учитывать уровень вложенности комментария, при входе в блок (/*) увеличивать уровень, при выходе из блока (*/) уменьшать уровень (если он больше нуля). И учитывать (выводить, копировать...) символы только если уровень равен нулю.
accept
4838 / 3237 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
15.09.2011, 02:45     Удалить комментарии из строки #11
у villu правильный подход, можно меньше букв сделать
Удалить комментарии из файла. Помогите найти ошибку.
talis
 Аватар для talis
789 / 541 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
15.09.2011, 10:41     Удалить комментарии из строки #12
villu,

Цитата Сообщение от villu Посмотреть сообщение
"Kirje sinulle /* а это комент, да */ kyllд! siina kaiiki; конец коммента */ siina kaikki."

Kirje sinulle siina kaikki.
а разве конец коммента не должен быть после слова "да"?
villu
202 / 202 / 4
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
15.09.2011, 12:46     Удалить комментарии из строки #13
а разве конец коммента не должен быть после слова "да"?
первый вариант так и работал.
второй вариант сделал "жадным" (до последнего валидного закрытия без открытия.)
первый вариант выглядит немного страшнее, но тоже ничего сложного.

один цикл без рекурсий.
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
65
66
67
68
69
std::string remove_comment(const std::string &in) {
 
    enum state_t {
        state_clean = 0,
        state_rem
    } state = state_clean;
 
    typedef std::string::const_iterator strcitr;
    struct str_tok {
        enum {
            token_open = 0,
            token_close,
            token_def
        } token;
        str_tok(): token(token_def) {}
        const strcitr operator()( const strcitr &input, const strcitr &end ) {
            strcitr next_itr;
            if((input != end) && ((next_itr = input + 1) != end)) {
                const char cur = *input;
                const char next = *next_itr;
                switch( cur ) {
                    case '/':
                        if(next == '*') {
                            token = token_open;
                            return next_itr;
                        }
                        break;
                    case '*':
                        if(next == '/' && (token != token_close) ) {
                            token = token_close;
                            return next_itr;
                        }
                        break;
                }
            }
            token = token_def;
            return input;
        }
    } get_tok;
 
    std::string out;
    strcitr itr;
 
    out.reserve(in.size());
    int opened = 0;
 
    for(itr = in.begin(); itr!=in.end(); itr = get_tok(++itr, in.end())) {
        switch( state ) {
        case state_clean:
            if( get_tok.token == str_tok::token_open ) {
                opened++;
                state = state_rem;
            } else if( get_tok.token == str_tok::token_close ) {
                out += "*/";
            } else {
                out.push_back(*itr);
            }
            break;
        case state_rem:
            if( get_tok.token == str_tok::token_close ) {
                if(--opened == 0) state = state_clean;
            } else if(get_tok.token == str_tok::token_open) {
                ++opened;
            }
            break;
        }
    }
    return out;
}
Кстати в варианте xAtom ошибка
C++
1
 char test[] = "1234/**/*/**/56789";
ожидаемо 1234*56789
получается 1234/**/*56789
или как пример "1234/**//**//*56789"
ожидаемо 1234
выводит без изменений. Хотя если принять такую строку за невалидную, то все в норме.

Добавлено через 21 минуту
Кстати в варианте xAtom ошибка
и еще одна
"***/" некорректно обрабатывает.
PointsEqual
ниначмуроФ
 Аватар для PointsEqual
832 / 516 / 33
Регистрация: 12.10.2009
Сообщений: 1,915
15.09.2011, 12:47     Удалить комментарии из строки #14
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<iostream>
#include<algorithm>
 
using namespace std;
 
int main()
{
    string  s = "asdasd /* asd /*123*/ dsa*/ asdasd";
 
    int f = s.find_first_of("/*");
    int l = s.find_last_of("*/");
 
    cout << s << endl;
 
    s.erase(f, l - f + 1);
 
    cout << s;
 
    return 0;
}
talis
 Аватар для talis
789 / 541 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
15.09.2011, 12:50     Удалить комментарии из строки #15
PointsEqual, а если так:

hello, /* world!*/ my /*car*/friend!

должно быть hello, my friend, а получится hello, friend

Добавлено через 24 секунды
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
#include <iostream>
#include <string>
 
using namespace std;
 
string nocomment( string str )
{
    string data;
    unsigned int level = 0;
 
    string::const_iterator it = str.begin();
 
    while( it != str.end() )
    {
        if( *it == '/' )
        {
            it++;
 
            if( *it == '*' )
            {
               level++;
               it++;
               continue;
            }
 
            if( !level )
               data += '/' + *it;
        }
        else if( *it == '*' )
        {
            it++;
 
            if( *it == '/' )
            {
               if( level )
                  level--;
 
               it++;
               continue;
            }
 
            if( !level )
               data += '*' + *it;
            else
               continue;
        }
        else if( !level )
           data += *it;
 
        it++;
    }
 
    return data;
}
 
int main()
{
    cout << "output: " << nocomment( "Hello, /*world*/sailor! How /* is /* your /* comment */ */ doing?**/do/* */ you/***/ do?" );
 
    return 0;
}
villu
202 / 202 / 4
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
15.09.2011, 12:56     Удалить комментарии из строки #16
нерабочий код
C++
1
2
char test0[] = "***/";
char test1[] = "132/**/*/**/456789";
1: T
2: 132Tc56789

c char test1[] = "132/*comment*/*/*comment*/456789"

вообще что-то непонятное
132Нomment456789
talis
 Аватар для talis
789 / 541 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
15.09.2011, 13:52     Удалить комментарии из строки #17
villu, глюки из-за string::operator+= применительно к char.

Вот исправленный вариант.

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
65
66
67
68
69
70
71
string nocomment( char * str )
{
    int level = 0;
    string out;
 
    char prev = 0,
         buff[2] = {0, 0};
 
    for( char *p = str; *p; p++ )
    {
        //cout << '\n' << *p << ": ";
 
        if( *p == '/' )
        {
            if( prev == '*' ) // закрываюший коммент
            {
                if( !level )
                {
                   prev = 0;
                   //cout << "closing comment outside of comment area ";
                   out += "/";
                   continue;
                }
 
                level--;
                prev = 0;
 
                //cout << "closing comment. level is now " << level << ' ';
 
                continue;
            }
 
            prev = *p;
            continue;
        }
        else if( *p == '*' )
        {
            if( prev == '/' ) // открываюший коммент
            {
                level++;
 
                //cout << "opening comment. level is now " << level << ' ';
 
                prev = 0;
                continue;
            }
 
            prev = *p;
 
            //continue;
        }
 
        if( !level )
        {
            prev = *p;
            buff[0] = *p;
            out += buff;
        }
    }
 
    return out;
}
 
int main()
{
    cout << "output: " << nocomment( "Hello, /*world*/sailor! How /* is /* your /* comment */ */ doing?**/do/* */ you/***/ do?" )
         << '\n' << nocomment( "***/" ) <<
         '\n' << nocomment( "132/**/*/**/456789" );
 
    return 0;
}
Единственное - непонятно, что вы ожидаете увидеть в строке

/**/*/**/

Цвета:
Открывающий, закрывающий, закрывающий вне комментария, просто текст

Если я понял правильно, тогда будет так:

*/**/

(закрывающий вне коммента, просто текст, опять закрывающий вне коммента)
villu
202 / 202 / 4
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
15.09.2011, 14:05     Удалить комментарии из строки #18
нет не павильно

/**/*/**/

YellowGreen - открыт
DarkOrchid - закрыт

у меня, кстати в коде тож косяк

1234/**/***/**/56789
должно получиться
1234***56789

поправил.
talis
 Аватар для talis
789 / 541 / 37
Регистрация: 11.05.2010
Сообщений: 1,298
Записей в блоге: 1
15.09.2011, 14:09     Удалить комментарии из строки #19
villu, вот два выражения:

/**/*/**/
/**/*/**/

в первом случае приоритет имеет */, как "закрывающий", а во втором - /*, как "открывающий". как их отличать-то?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.09.2011, 14:11     Удалить комментарии из строки
Еще ссылки по теме:

Удалить из строки комментарии вида '/* . */". Игнорировать вложенные комментарии C++
C++ Удалить комментарии из фаила
С помощью итераторов удалить комментарии из текста программы C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
villu
202 / 202 / 4
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
15.09.2011, 14:11     Удалить комментарии из строки #20
talis зайди в ЛЮБОЙ редактор, который умеет подсвечивать такие комменты и посмотри.

и ситуацию с 1234/**/***/**/56789 тоже посмотри.
Yandex
Объявления
15.09.2011, 14:11     Удалить комментарии из строки
Ответ Создать тему
Опции темы

Текущее время: 16:30. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru