Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Функция удаления лишних прбелов справа и слева


Автор: Voldemar2004 28.5.2006, 13:17
Есть ли в Си готовая функция, которая бы отсекала лишние пробелы (на подобие LTrim, RTrim, Trim в VB 6) ? А то я ничего не нашел и написал сам:
Код
//---------------------------------------------------------------------------
#include <iostream.h>
#include <conio.h>
#include <string.h>
//---------------------------------------------------------------------------
void main(void)
{

char *a = "     Stroka.          ";

        unsigned int i=0;

        for(i; a[i] == ' '; i++) {;}
        const CutLenLeft = i;  /* Позиция 1-го символа, отличного от пробела. */


        for(i=strlen(a); i--; i>0) {if( a[i] != ' ' ) break;}
        /* Позиция 1-го символа, отличного от пробела - заход справа. */
        const CutLenRight = i;

                char *NoSpace = "";

                i = CutLenLeft;
                for(unsigned int j=CutLenLeft; j<CutLenRight+1; j++)
                {
                 NoSpace[j] = a[i];
                 i++;
                 cout<<NoSpace[j];
                }


getch();
}
//---------------------------------------------------------------------------
И еще: чего-то не получается сделать из этого кода функцию типа этого:
Код
char *NoSpace(char *a)
{

/* тело функции */


return NoSpace;
}
 

Автор: Darhazer 28.5.2006, 14:33
Готовая функция думаю нету, но нашел вот такое STL решение:

Код

std::string trim(std::string const& source, char const* delims = " \t\r\n") {
  std::string result(source);
  std::string::size_type index = result.find_last_not_of(delims);
  if(index != std::string::npos)
    result.erase(++index);

  index = result.find_first_not_of(delims);
  if(index != std::string::npos)
    result.erase(0, index);
  else
    result.erase();
  return result;
}


А еще у http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmfc98/html/_mfc_cstring.asp есть методи TrimLeft и TrimRight 

P.S. или ти спрашиваеш про C, а не про C++? 

Автор: LPBOY 28.5.2006, 14:48
Вот моя версия
Код

#include <iostream>
#include <cstring>

char* trim(const char* s)
{
    const char SPACE = ' ';
    int i = 0, j;
    for(; s[i] == SPACE; ++i);
    if (s[i] == 0) return new char[1]();//возвращаем "".

    for(j = strlen(s) - 1; s[j] == SPACE; --j);
    int sz = j - i + 2;
    char* new_s = new char[sz];
    strncpy(new_s, s + i, sz - 1);
    new_s[sz - 1] = 0;
    return new_s;
}

int main()
{
    char str[] = "  string   ";
    char *s = trim(str);
    std::cout << s << '\n';

    delete [] s;
    return 0;
}


STL-версия: http://blogs.msdn.com/marcod/archive/2005/07/08/StdTrim.aspx

 Voldemar2004, писать в такую строку
Код

char *NoSpace = "";

нельзя. Это просто указатель, никакой памяти не выделялось, разве что для константной литеральной строки "" размером 1, в которую также писать нельзя.
Надо делать или так
Код

char str[size];

если размер известен во время компиляции, иначе так
Код

char* str = new char[size];
  

Автор: Voldemar2004 3.6.2006, 12:45
Цитата(LPBOY @  28.5.2006,  15:48 Найти цитируемый пост)
Voldemar2004, писать в такую строку нельзя.
Пардон, это я сглупил. Вот исправил:
Код
#include <iostream.h>
#include <conio.h>
#include <string.h>

char *NoSpace(char *a)
{
unsigned int i=0;

        for(i; a[i] == ' '; i++) {;} /* Пока не встретится символ пробела. */

        const CutLenLeft = i;        /* Номер 1-го элемента, не равного ' '. */

        /* Номер 1-го элемента, не равного ' ' - просмотр справа. */
        for(i=strlen(a); i--; i>0) {if( a[i] != ' ' ) break;}

                const CutLenRight = i;

                /* Число символов, включая пробелы
                без левых и правых крайних пробелов. */
                int length = CutLenRight - CutLenLeft + 1;

                        if(length) /* Если есть хотя бы один пробел. */
                        {
                         /* В новый массив запишем результат. */
                         char *b = new char[length];

                                unsigned int j=0;

                                for(i=CutLenLeft; i<CutLenRight+1; i++)
                                {
                                b[j] = a[i];
                                j++;
                                }

                        return b;

                        delete[] b; /* char *b    */
                        }                /* if(length) */
}

void main(void)
{

cout<<NoSpace("     Hello, World!   ");

getch();
}


Цитата(Voldemar2004 @  28.5.2006,  14:17 Найти цитируемый пост)
не получается сделать из этого кода функцию типа этого:
А это потому, что у меня присутствует:
Код
char *NoSpace = "";
 - памяти не выделилось, как верно заметил LPBOY, и это же значение я пытался возвратить.

Как думаете, есть еще недочеты?

LPBOY, в этой строке у тебя по-моему ошибка:
Код
if (s[i] == 0) return new char[1]();//возвращаем "".
Или я чего-то не понял, зачем круглые скобочки после переопределения размера массива? LPBOY, если я возвращу такое значение
Код
cout<<trim("");
то компилятор цепляет мусор (причем каждый компилятор - свой).

Цитата(Darhazer @  28.5.2006,  15:33 Найти цитируемый пост)
P.S. или ти спрашиваеш про C, а не про C++? 
Я спрашивал, есть ли функция наподобие int strlen(char *) из библиотеки string или другой библиотеки, которая отсекала бы пробелы. 

Автор: LPBOY 5.6.2006, 19:17
Цитата(Voldemar2004 @  3.6.2006,  12:45 Найти цитируемый пост)
Как думаете, есть еще недочеты?

Компилировать я не пробовал, но вот, что бросается в глаза...

(строка 9) for(i; a[i] == ' '; i++) {;} 
Зачем нужно выделенное? Это, конечно, не ошибка, но абсолютно бесполезно.

(11) const CutLenLeft = i;  //надо const int CutLenLeft = i;
Не забывай указывать тип, компиляторы строго придерживающиеся стандарта такое не скомпилируют.

(14) for(i=strlen(a); i--; i>0)
Наверно, ты имел в виду вот так: for(i=strlen(a); i>0; i--)   ;)
Хотя более правильно будет так:
for(i=strlen(a) - 1; i>=0; i--)

(37) delete[] b;
Эта строчка никогда не выполнится. Да и в любом случае очищать память должна вызывающая сторона.

Для случая, когда length равно нулю, и блок if не выполняется, нет соответствующего return.

Память, выделенная для новой строки, не очищается, надо сделать как-то так:
Код

char* s = NoSpace("     Hello, World!   ");
cout << s;
delete[] s;


Цитата(Voldemar2004 @  3.6.2006,  12:45 Найти цитируемый пост)
зачем круглые скобочки после переопределения размера массива?

По идее они должны обнулять массив. Хотя старые компиляторы могут не знать про такой синтаксис. Это можно переписать вот так:
Код

if (s[i] == 0) 
{
    char* t = new char[1];
    t[0] = 0;
    return t;
}


Цитата(Voldemar2004 @  3.6.2006,  12:45 Найти цитируемый пост)
если я возвращу такое значение то компилятор цепляет мусор

У меня, вроде, правильно отрабатывает. 

Автор: Voldemar2004 6.6.2006, 13:51
Цитата(LPBOY @  5.6.2006,  20:17 Найти цитируемый пост)
Не забывай указывать тип, компиляторы строго придерживающиеся стандарта такое не скомпилируют.
Цитата(LPBOY @  5.6.2006,  20:17 Найти цитируемый пост)
По идее они должны обнулять массив. Хотя старые компиляторы могут не знать про такой синтаксис.
Я использовал Borland C++ 5.02 (не Builder) и KDevelop. Ни о каких ошибках они меня не предупреждали. LPBOY, а ты какой компилятор используешь? 

Автор: LPBOY 6.6.2006, 14:42
gcc выдает ошибку. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)