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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 64, средняя оценка - 4.75
Zion3439
2 / 2 / 0
Регистрация: 04.03.2009
Сообщений: 30
#1

Удаление лишних пробелов в начале и конце строки. - C++

04.03.2009, 13:31. Просмотров 8079. Ответов 28
Метки нет (Все метки)

Нужно написать функцию char*alltrim(char*string) для удаления пробелов в начале и конце строки с помощью указателей. Помогите завершить задачку.
Возник ряд вопросов:
1) как создать какую-то произвольную переменную типа char ( у меня это p)и записать туда из строки string подстроку начиная с определённого элемента заканчивая другим элементом с помощью указателей? Надо ли в конце этой строки p записать NULL?
2)Как потом эту произвольную переменную ( у меня это p) вернуть как результат работы функции заместо переменной string?
3) Как вобще правильно описать переменную размер которой неизвестен?
Вот чего получилось добится:
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
#include <iostream.h>
char*alltrim(char*string)
 {
  int i=0,d=0,c=0,g=0;
  while(*string==' ')  // Считается количество пробелов в начале строки - i
  {
   c=c+1;
   i=i+1;
   *string++;
  }
  while(*string) // Считается количество пробелов в конце строки - d
  {
   if (*string!='\x0')
   {
    if (*string==' ') d=d+1;
    else d=0;
    c=c+1;
    *string++;
   }
  }
  char*p="";
  for(g=c-i;g>d;g--) // Неверная функция. Копируется подстрока без начальных и           конечных пробелов
   *p++=*(string-g);
   return p;
 }
 
 
void main(void)
 {
  clrscr();
  char*x="      q   w   e r       t     y      ";
  *alltrim(x); //На выходе должно получится  "q   w   e r       t     y"
  
 }
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
accept
4821 / 3241 / 165
Регистрация: 10.12.2008
Сообщений: 10,682
05.03.2009, 13:18     Удаление лишних пробелов в начале и конце строки. #16
Код
*--endp == ' '
он сдвинул влево, проверил если там пробел
если пробел - зашёл в цикл поставил ноль, иначе не зашёл в цикл

а у тебя он сдвинул влево, зашёл допустим потому что там пробел, сдвинул вправо поставил ноль и опять сдвигает влево, то есть находит тот же пробел
easybudda
Эксперт CЭксперт С++
9465 / 5478 / 927
Регистрация: 25.07.2009
Сообщений: 10,502
13.08.2009, 19:21     Удаление лишних пробелов в начале и конце строки. #17
Примерно то же самое, но не работает:
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
#include <stdio.h>
#include <ctype.h>
#include <string.h>
 
/* char *trunc_str(char *) - должна бы выдавать указатель на строку без начальных и конечных пробелов */
char *trunc_str(char *str){
    char *start;
    char *stop;
 
/* Не работает! */
    for ( start = str; isspace(*start); start++ )
        ;
/* Работает... */
    for ( stop = str + strlen(str) - 1; isspace(*stop) && stop > start; stop-- )
        ;
    *++stop = 0;
 
    return start;
}
 
int main(){
    char buf[BUFSIZ];
 
    while ( fgets(buf, BUFSIZ, stdin) ) {
        trunc_str(buf);
        if ( buf ) printf("\"%s\"\n", buf);
    }
/* Пробелы в начале строки остаются, в конце удаляются */
 
    return 0;
}
Извиняюсь, я всё понял!
C
1
2
3
while ( fgets(buf, BUFSIZ, stdin) ) {
        printf("\"%s\"\n",trunc_str(buf));
    }
Gravity
562 / 556 / 39
Регистрация: 29.01.2009
Сообщений: 1,274
13.08.2009, 19:27     Удаление лишних пробелов в начале и конце строки. #18
C
1
2
3
/* Не работает! */
        for ( start = str; isspace(*start); start++ )
                ;
А почему оно должно работать, если цикл пустой.

Добавлено через 55 секунд
О, и я все понял
easybudda
Эксперт CЭксперт С++
9465 / 5478 / 927
Регистрация: 25.07.2009
Сообщений: 10,502
13.08.2009, 19:39     Удаление лишних пробелов в начале и конце строки. #19
Кстати, можно и короче

C
1
2
3
4
5
6
7
8
9
10
char *trunc_str(char *str){
    char *stop;
    for ( ; isspace(*str); str++ )
        ;
    for ( stop = str + strlen(str) - 1; isspace(*stop) && stop > str; stop-- )
        ;
    *++stop = 0;
 
    return str;
}
Добавлено через 3 минуты 41 секунду
Цитата Сообщение от Gravity Посмотреть сообщение
C
1
2
3
/* Не работает! */
        for ( start = str; isspace(*start); start++ )
                ;
А почему оно должно работать, если цикл пустой.

Добавлено через 55 секунд
О, и я все понял
Оно на самом деле работает, а цикл пустой - так в нём start++ пока isspace(*start) от него больше и не нужно. Я в printf по сути обрезанную с конца buf передавал, а так всё получилось. Ну разве что пустые строки неправильно обрабатываются - указатель на "\n" получается. Можно поправить, можно отслеживать...
sledge
0 / 0 / 0
Регистрация: 27.07.2009
Сообщений: 13
14.08.2009, 00:45     Удаление лишних пробелов в начале и конце строки. #20
Если еще актуально, я просто для себя разбирался, прокомментировал заодно:
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
#include <iostream.h>
//#include <conio.h>
//#include <string.h>
//#include <alloc.h>
 
char* alltrim( char*string)
{
int i=0,d=0,c=0,g=0,j=0;
while(*string==' ')
{
    c=c+1;      //total_length
    i=i+1;      //spaces_before
    string++;   //было *string++; *string++ - значит получить значение(char)на   которое сейчас указывает string а после этого увеличить указательна на один .
//достаточно просто увеличить указатель
}
while(*string)
{
    if (*string!='\x0')// Этот if не нужен. *string!='\x0' можно перенести в while
    {                  // либо вообще убрать
        if (*string==' ') d=d+1;//spaces_after
        else d=0;
        c=c+1;              //total_length
        string++;           //было *string++;
    }
}
char*p=new char[c-d-i+1];// выделение памяти
for(g=c-i;g>d;g--) p[j++]=*(string-g); // сердце функции хитрое какое :-)
p[j]='\0';
cout<<"_"<<p<<"_"<<endl; //тут выводит всё как надо - "q w e r t y"(без пробелов по бокам)
return p;       // функция возвращает указатель, его нужно присвоить такому же указателю такого ж
                // типа, после окочания работы функии указатель p уничтожается и на выделенную
                //выше память никто не указывает - она утекла.
}
int main(void)
{
//clrscr();
char*x=" q w e r t y ";
//*alltrim(x);  тут ты просто вызвал функцию она себе отработала, создала локальную переменную p,
                //которая после возврата из функции умерла.
char *result;
result=alltrim(x); //  тут обЪявляется и инициализируется указатель который и словит значение p.
cout<<"_"<<result<<"_"; //а тут почему-то уже выводит - " q w e r t y " (с пробелами по бокам)return 0;
}
Rififi
2359 / 1054 / 44
Регистрация: 03.05.2009
Сообщений: 2,656
14.08.2009, 01:40     Удаление лишних пробелов в начале и конце строки. #21
Кстати, можно и короче

char *trunc_str(char *str){
char *stop;
for ( ; isspace(*str); str++ )
;
for ( stop = str + strlen(str) - 1; isspace(*stop) && stop > str; stop-- )
;
*++stop = 0;

return str;
}
Кстати, отличный индусский код. Его использование может быть таким:

char* p = new char[100];
strcpy(p, " 123 ");
p = trunc_str(p);
delete [] p;

...
Если еще актуально, я просто для себя разбирался, прокомментировал заодно:
char* alltrim( char*string)
{ ...
...
char* trimall2(char* str){ ...
Эти два кода примерно аналогичны. вряд ли юзер будет ожидать дополнительных аллокаций.

char*x=" q w e r t y ";
std::cout<<alltrim(x); //На выходе должно получится "q w e r t y"
а вот за такое надо отрывать руки и отправлять обратно на родину, в Олбанию :LOL:

а теперь - правильный вариант (:

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 <tchar.h>
#include <string.h>
 
TCHAR* trim_left(TCHAR* const str)
{
    if (str == NULL)
        return (NULL);
    const size_t len = _tcslen(str);
    const size_t pos = _tcsspn(str, _T(" \t\r\n"));
    if (pos > len || pos == 0)
        return (str);
    memmove(str, str + pos, (len - pos) * sizeof(TCHAR));
    str[len-pos] = _T('\0');
    return (str);
}
 
TCHAR* trim_right(TCHAR* const str)
{
    if (str == NULL)
        return (NULL);
    TCHAR* p = str + _tcslen(str) - 1;
    while ((p >= str) && _istspace(*p))
        *p-- = _T('\0');
 
    return (str);
}
 
TCHAR* trim(TCHAR* const str)
{
    return trim_left(trim_right(str));
}
 
int main()
{
    TCHAR* p = new TCHAR[100]();
    _tcscpy(p, _T(" \t\r\n\n\r  1 2 3   \r\r\n\n\t"));
    trim(p);
    delete [] p;
 
    return (0);
}
odip
Эксперт С++
7157 / 3297 / 59
Регистрация: 17.06.2009
Сообщений: 14,164
14.08.2009, 11:45     Удаление лишних пробелов в начале и конце строки. #22
а теперь - правильный вариант (:
А вот кстати не очень правильный.
1) Если уже хочется скорости - то писать надо сразу trim двойной - слева и справа.
2) tcslen() вызывать два раза совершенно не нужно.
Собственно не нужно вызывать ни одного раза.
3) В условии просили удалить только пробелы.
4) TCHAR - это круто, но насчет Unicode опять же никто не говорил.
5) istspace(), tcsspn() - тоже не нужно вызывать.

А вот memmove() похоже пригодится - возможно будет быстрее, чем без него.
-=ЮрА=-
Заблокирован
Автор FAQ
14.08.2009, 12:46     Удаление лишних пробелов в начале и конце строки. #23
Выкладываю то что у меня получилось...
Исходный текст содержится в текстовике, подстрока находится между словами в тексте begin и end. Если этих слов в текстовике нето, то подстрока не извлекается. Привожу также результат работы и текстовики (их названия говорят сами за себя)
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
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
#include <windows.h>
#include <shlobj.h>
#include <stdio.h>
 
//Возвращает подстроку из chBuf 
//sLeft  - указатель на 0-й элемент подстроки в строке chBuf
//sRight - указатель на последний элемент подстроки в строке chBuf
 
//Поясняю
//chBuf = "123456aa789";
//Допустим надо вернуть аа
//sLeft = strchr(chBuf,'a');
//sRight= strrchr(chBuf,'a');
//Это всего лиш пример
//sLeft можно задать как aa789 а sRight как a789
char * GetMidStr(LPCTSTR chBuf, char * sLeft, char * sRight);
 
//Чистка пробелов
char * TrimSpace(char * str);
 
//Для выбора файла с текстом
LPTSTR SelectFile();
 
char * str = (char *)malloc(sizeof(char));
 
FILE *f;
 
void main()
{
    int sLen = 0;
    char * sLeft, * sRight, * chBuf;
    char sPath[MAX_PATH];sPath[0] = '\0';
    if(sprintf(sPath,SelectFile()))
    {
        if((f = fopen(sPath,"rb+")))
        {
            fseek(f,0,SEEK_END);
            sLen = ftell(f);
            fseek(f,0,SEEK_SET);
            str = (char *)realloc(str,sLen);
            //считываем строку для анализа
            fread(str,1,sLen,f);
            str[sLen - 1] = '\0';
            fclose(f);
            printf("INPUT str : %s\r\n",str);
            sLen = (int)(&str[0]);//Запоминаем начало строки
            //верней запоминаем адресс начала
            //нужно чтоб realloc потом сработал!!!!
            str = TrimSpace(str);
            printf("TRIMS str : %s\r\n",str);
            //Допустим нам нужна подстрока которая начинается
            //со слова begin и оканчивается словом end
            //одновременно проверим есть ли такая подстрока вообще
            sLeft = strstr(str,"begin");
            sRight = strstr(str,"end");
            if(!sLeft)
                printf("str isn't contain word [begin]\r\n");
            else
            {
                if(!sRight)
                    printf("str isn't contain word [end]\r\n");
                else
                {
                    chBuf = GetMidStr((LPCTSTR) str, sLeft, sRight);
                    printf("SUBSTRING : %s\r\n",chBuf + strlen("begin"));
                    //Тут чёт free выделывается, даж сам не пойму((((
                    //free(chBuf);
                }
            }
            str -= ((int)&str[0] - sLen);
            str = (char *)realloc(str,sizeof(char));
        }
    }
    printf("Enter NUM1 to choose next file with text\r\n");
    scanf("%d",&sLen);
    if(sLen == 1)
        main();
}
 
char * GetMidStr(LPCTSTR chBuf, char * sLeft, char * sRight)
{
    char * RetVal;
    int sLen = chBuf != NULL ? strlen(chBuf) : -1;
    if(0 < sLen)
    {
        RetVal = (char *)malloc((sLen + 1)*sizeof(char));
        sprintf(RetVal,"%s",chBuf);
        if(*sLeft && *sRight)
        {
            RetVal = strstr(RetVal,sLeft);
            if(RetVal)
            {
                sLen = strlen(sLeft) - strlen(sRight);
                if(0 < sLen)
                    RetVal[strlen(RetVal) - strlen(sRight)] = '\0';
            }
        }
    }
    return RetVal;
    //После использования в проге 
    //обязательно надо предусмотреть чистку памяти!!!!
    //Вот вариант реализации чистки
    //char * someStr = GetMidStr(...);
    //if(someStr)
    //   free(someStr);
}
 
//Думаю так наиболее просто обрезать пробелы
char * TrimSpace(char * str)
{
    char * chBuf = strrchr(str,' ');
    if(chBuf)
        str[strlen(str) - strlen(chBuf) - 1] = '\0';
    if(str)
        while(str[0] == ' ')
            str++;
    return str;
}
 
LPTSTR SelectFile()
{
    char sPath[MAX_PATH];sPath[0] = '\0';
    LPCITEMIDLIST lpItemDList;
    BROWSEINFO bi = {NULL, NULL, sPath,
       "Выберите файл для обработки",
        BIF_DONTGOBELOWDOMAIN|BIF_BROWSEINCLUDEFILES,
        NULL,
        NULL,
        0
    };
    if((lpItemDList=SHBrowseForFolder(&bi)))
    {
        if(SHGetPathFromIDList(lpItemDList, sPath))
            GetShortPathName((LPCTSTR)sPath,sPath,strlen(sPath));
    }
    return &sPath[0];
}
Миниатюры
Удаление лишних пробелов в начале и конце строки.  
Вложения
Тип файла: txt begin_end.txt (62 байт, 21 просмотров)
Тип файла: txt no_begin.txt (56 байт, 18 просмотров)
Тип файла: txt no_end.txt (58 байт, 18 просмотров)
Rififi
2359 / 1054 / 44
Регистрация: 03.05.2009
Сообщений: 2,656
14.08.2009, 14:31     Удаление лишних пробелов в начале и конце строки. #24
odip,
А вот кстати не очень правильный.
1) Если уже хочется скорости - то писать надо сразу trim двойной - слева и справа.

А кто сказал что я хочу скорости? Для меня на первом месте - стабильность. А скорости я захочу тогда, когда профайлер покажет что это самое тормозное место в программе.

2) tcslen() вызывать два раза совершенно не нужно.
Собственно не нужно вызывать ни одного раза.

попробуй как нибудь переместить область памяти, не зная её размера

3) В условии просили удалить только пробелы.
в том и фишка, только пробелы, или ещё табы etc - код не меняется. так зачем выкладывать недоделанную кривульку, если можно сдлелать как надо (Ж

4) TCHAR - это круто, но насчет Unicode опять же никто не говорил.
см. выше.

5) istspace(), tcsspn() - тоже не нужно вызывать.
а что нужно вызывать?

PS. И вот еще - если ты возьмешь на вооружение хотя бы эти два правила, многое откровется для тебя с совершенно новой стороны (((((((:

1. Помните, что любой код может быть тщательно исследован и, возможно, атакован. Это нормально. На ваш код нападают, и ничего страшного в этом нет. Однако главный вопрос заключается в том, будет ли ваш код уязвим? Ответ на этот вопрос зависит от вас. Поэтому вы должны гордиться своим кодом. Вы должны быть довольны качеством своего кода и спокойно спать ночью, зная, что, если он будет атакован, вы сделали все возможное, чтобы защитить его от взлома.
2. Я уже говорил это миллион раз и повторю снова: все входящие данные – зло, пока не доказано обратного. Если посмотреть на самые ужасные уязвимости безопасности, все они имеют общую черту: разработчик доверял поступающим данным. Проблема состоит в том, что, если ваш код предполагает, что данные формально правильны, что же случится, если ваше предположение неверно? Если вам повезет, то в вашем приложении может просто произойти сбой. А если не повезет, то взломщик может внедрить в ваш процесс вредоносный программный код и причинить ущерб
easybudda
Эксперт CЭксперт С++
9465 / 5478 / 927
Регистрация: 25.07.2009
Сообщений: 10,502
14.08.2009, 16:11     Удаление лишних пробелов в начале и конце строки. #25
Цитата Сообщение от odip Посмотреть сообщение
5) istspace(), tcsspn() - тоже не нужно вызывать.
isspace - оно же макрос... ну не хотите - не вызывайте:

C
1
2
3
4
...
for ( ; *str == ' ' || *str == '\t'; str++ )
;
...
odip
Эксперт С++
7157 / 3297 / 59
Регистрация: 17.06.2009
Сообщений: 14,164
14.08.2009, 16:29     Удаление лишних пробелов в начале и конце строки. #26
isspace - оно же макрос
Ладно - isspace() можно вызывать.
Насколько помню макрос этот разворачивается в обращение к массиву,
что работает быстрее чем два сравнения.

Хотя еще раз повторю: в исходном условии идет речь о пробелах.

Добавлено через 10 минут 29 секунд
PS. И вот еще - если ты возьмешь на вооружение хотя бы эти два правила, многое откровется для тебя с совершенно новой стороны (((((((:
Это ты случайно не Маерса тут цитируешь ?
Книжка называется типа "Написание надежных программ".
Книжке лет 40, но она до сих пор актуальна.

Добавлено через 1 минуту 36 секунд
попробуй как нибудь переместить область памяти, не зная её размера
Я хотел сказать, что если ты будешь обрабатывать оба конца строки,
то ты должен найти второй конец в любом случае - чтобы открутить пробелы справа от конца. А раз ты нашел конец строки - ты знаешь длину строки.
Нет большой необходимости считать длину.

Добавлено через 1 минуту 33 секунды
а что нужно вызывать?
isspace() еще туда-сюда.
А вот tcsspn() думаю сильно тормознутая функция.
firefox1913
27 / 27 / 2
Регистрация: 01.07.2009
Сообщений: 58
14.08.2009, 19:28     Удаление лишних пробелов в начале и конце строки. #27
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
#include <iostream>
#include <cstring>
using namespace std;
char *allgoritm(char *str)
{
 int beg,end,i;
 for(i=0; i < strlen(str); i++)
  if(*(str+i)!=' ')
  {
    beg=i;
    break;
  }
 for(i=strlen(str)-1; i >=0; i++)
  if(*(str+i)!=' ')
  {
    end=i;
    break;
  }
 char *st=new char[strlen(str)];
 int j=0;
 for(i=beg; i <=end; i++)
 {
  *(st+j)=*(str+i);
  j++;
 }
 *(st+j+1)='\0';
 return st;
}
int main()
{
    char str[256],*s;
    cin.getline(str,256);
    s=allgoritm(str);
    cout<< s <<endl;
    return 0;
}
Rififi
2359 / 1054 / 44
Регистрация: 03.05.2009
Сообщений: 2,656
15.08.2009, 01:34     Удаление лишних пробелов в начале и конце строки. #28
odip,
Ладно - isspace() можно вызывать.
мая имеет благодарить, насяльника! (D

Это ты случайно не Маерса тут цитируешь ?
http://msdn.microsoft.com/ru-ru/magazine/cc163518.aspx

но ты должен найти второй конец в любом случае
и как же мне это сделать?

А вот tcsspn() думаю сильно тормознутая функция.
think different
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.03.2010, 16:51     Удаление лишних пробелов в начале и конце строки.
Еще ссылки по теме:
C++ Удаление лишних пробелов с помощью вспомогательного массива
C++ Удалить пробелы в начале и конце строки
Функция удаляющая пробелы в начале и в конце строки C++
Во введенной пользователем строке удалите все пробелы в начале и конце строки C++
Удаление лишних (подряд идущих) разделителей при разделении строки C++

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

Или воспользуйтесь поиском по форуму:
alter-sl
Сообщений: n/a
30.03.2010, 16:51     Удаление лишних пробелов в начале и конце строки. #29
Цитата Сообщение от Humanitis Посмотреть сообщение
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
char*alltrim(char*string)
 {
    char *p,*iter;
    while(*string++==' ');
    iter=--string;
    while(*iter)iter++;
    while(*(--iter)==' ');
    p=new char[iter-string+1];
    char *result=p;
    while(string<=iter)*p++=*string++;
    *p=0;
   return result;
 }
 
int main(void)
 {
  char*x="      q   w   e r       t     y    ";
  std::cout<<alltrim(x); //На выходе должно получится  "q   w   e r       t     y"
  system("pause");
  return 0;
 }
Не мог бы ты написать комментарии к каждой строке?просто я только начинаю изучать язык и не до конца понял как она работает)только основную идею уловил... Буду очень благодарен! Заранее Спасибо!
Yandex
Объявления
30.03.2010, 16:51     Удаление лишних пробелов в начале и конце строки.
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru