Предыдущая тема :: Следующая тема |
Автор |
Сообщение |
Tahir Гость
|
Добавлено: Вт Апр 01 2003 16:05 Заголовок сообщения: Как из char-строки удалить все пробелы? |
|
|
Как из char-строки удалить все пробелы? Приложение на VC++. |
|
Вернуться к началу |
|
|
GREA
Зарегистрирован: 14.05.2003 Сообщения: 758 Откуда: Новосибирск
|
Добавлено: Ср Апр 02 2003 13:30 Заголовок сообщения: Re: Как из char-строки удалить все пробелы? |
|
|
Строка есть массив. Создай второй массив и копируй туда посимвольно из первого массива (на нужные места), проверяя на пробелы. Стандартной функции вроде нет. |
|
Вернуться к началу |
|
|
Tahir Гость
|
Добавлено: Ср Апр 02 2003 14:03 Заголовок сообщения: Re: Как из char-строки удалить все пробелы? |
|
|
Это банально и некрасиво. Уже есть решение без посимвольного копирования. |
|
Вернуться к началу |
|
|
Petr Гость
|
Добавлено: Ср Апр 02 2003 15:18 Заголовок сообщения: Re: Как из char-строки удалить все пробелы? |
|
|
Оно реализовано в твоем верхнем вопросе? |
|
Вернуться к началу |
|
|
Tahir Гость
|
Добавлено: Ср Апр 02 2003 15:20 Заголовок сообщения: В каком верхнем? |
|
|
В каком верхнем? Есть char-массив с пробелами где угодно, по сколько угодно. После работы маленькой функции нет ни одного пробела. Указатель остается. |
|
Вернуться к началу |
|
|
GREA
Зарегистрирован: 14.05.2003 Сообщения: 758 Откуда: Новосибирск
|
Добавлено: Чт Апр 03 2003 07:13 Заголовок сообщения: Re: В каком верхнем? |
|
|
В string.h есть функция (забыл название), которая определяет адрес первого заданного символа (в нашем случае пробела). Возвращает указатель на этот пробел. Потом используешь strcat со смещение на следующий после пробела символ. |
|
Вернуться к началу |
|
|
_DM Гость
|
Добавлено: Пн Апр 07 2003 18:37 Заголовок сообщения: Re: Это Ответ !!!! |
|
|
Написать можно все в двух циклах один меньше другого и при этом без всяких дополнительных или встроенных функций. Ниже приведена реализация кода на VС++.
str -строка, указатель типа char или массив из символов. Строка обязательно должна кончатся нулем. int iGo=0;// индекс строки, от куда копируем символ. int iStr=0;// индекс строки, куда копируем символ. while(str[iStr]) { while(str[iGo]==' ')iGo++;//пропуск пробелов str[iStr]=str[iGo];//копирование символов iStr++; iGo++; } |
|
Вернуться к началу |
|
|
Tahir Гость
|
Добавлено: Вт Апр 08 2003 09:10 Заголовок сообщения: Есть и попроще вариант :) |
|
|
char* alltrim(char* A, ) { for (register int i=start; (int)strlen(A);i++) if (isspace(A[i])){ strcpy(A+i,A+i+1); i--; } return A; }
Кто проще придумает??? |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Вт Апр 08 2003 19:38 Заголовок сообщения: Попробую :) |
|
|
char* alltrim(char* A, ) { char *B=A, *C=A; while(*B) if(!isspace(*C++)) *B++=C[-1]; return A; } |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Вт Апр 08 2003 20:37 Заголовок сообщения: Маленькое уточнение :) |
|
|
char* alltrim(char* A) { char *B=A, *C=A; while(*B) if(!isspace(*C++)) if(*B=C[-1]) B++; return A; } |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Вт Апр 08 2003 20:44 Заголовок сообщения: Это ошибка !!!! |
|
|
>>int iGo=0;// индекс строки, от куда копируем символ. >>int iStr=0;// индекс строки, куда копируем символ. >>while(str[iStr]) >>{ >> while (str[iGo]==' ')iGo++;//пропуск пробелов >> str[iStr]=str[iGo];//копирование символов >> iStr++; >> iGo++;
После этого оператора str[iStr] может быть не нулевым и цикл продолжится
>>} |
|
Вернуться к началу |
|
|
Sclis Гость
|
Добавлено: Чт Апр 10 2003 12:05 Заголовок сообщения: Re: Маленькое уточнение :) |
|
|
void deltrim(char* s1){ for(char * s=s1;*s;s++) if (*s!=' ') *s1++=*s; *s1='\0'; } 1. если меняешь аргумент - возвращай его, а не функцию. если функция возвращает ссылку не меняй аргумент. не ошибка. просто мнение. чтобы не путаться с lvalue потом. 2. формальный параметр - ссылка, а не значение, но сама переменная-ссылка не та же, что в программе=> ее можно попользовать раз уж меняем аргумент, а не создаем новую строку. 3. последним штрихом - закрыть строку
а если надо возвращать строку и принимать аргументами даже константы: char * deltrim1(char* s1){ char *s=s1; int n=0; while(*s)if(*s++!=' ') n++;
char* s2=new(char[n+1]);
for(s=s2;*s1;s1++) if (*s1!=' ') *s2++=*s1; *s2='\0'; return s; } |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Пн Апр 14 2003 14:09 Заголовок сообщения: Маленькое уточнение с маленькой неточностью :) |
|
|
В решении есть маленькая неточность, которая может оказаться критичной, если в строке нет пробелов:
>>if (*s!=' ') *s1++=*s; когда при исполнении этой строки достигнут конец строки (то есть *s=='\0'), *s1 получает значение '\0' и перемещается на следующий символ, поэтому следующее присваивание >>*s1='\0'; _может_ заменить символ за пределами строки.
В подавляющем большинстве случаев это не важно, так как при наличии пробелов в исходной строке эта замена произойдет в пределах старой строки, а в отсутствии пробелов этот символ из-за выравнивания по блокам (параграфам) вероятнее всего окажется в хвостовой, неиспользуемой области, тем не менее полной гарантии этого нет. Поэтому возможно разрушение данных. Аналогичная неточность в варианте с возвращаемым указателем: >>if (*s1!=' ') *s2++=*s1; >>*s2='\0';
Эта неточность присутствует также в вариантах _DM 07-04-2003 19:37 и Борис 08-04-2003 20:38
Исправить неточность следует так: for (char *s=s1; *s; s++) if (*s!=' ') if (*s1=*s) s1++;
и получаем вариант, аналогичный варианту Борис 08-04-2003 21:37. Разница в моменте увеличения s (в конце или в середине цикла) и связанного с этим разыименования при занесении непробела (*s или s[-1]) |
|
Вернуться к началу |
|
|
Sclis Гость
|
Добавлено: Вт Апр 15 2003 04:40 Заголовок сообщения: Re: Маленькое уточнение с маленькой неточностью :) |
|
|
)) *s++=*s1 - "выполнить присваивание и ПОСЛЕ добавить единицу к s" для случая, когда инкремент надо выполнить ДО существует операция *(++s) . так, что логически испоняться код *s++=*s; будет абсолютно так же как if(*s=*s1)s++; просто он в записи короче и лишняя операция проверки условия отсутствует. Цикл не проходит при *s='/0'. поэтому и приходится закрывать строку дополнительной операцией в конце функции. Вобще, загони в компилятор и попробуй ) |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Вт Апр 15 2003 09:43 Заголовок сообщения: А вот как раз и нет! :) (+) |
|
|
>>логически исполняться код *s++=*s1; будет абсолютно так же как >>if(*s=*s1)s++; просто он в записи короче и лишняя операция проверки условия отсутствует.
Как раз не абсолютно: при *s++=*s1; s увеличивается ВСЕГДА, а при if(*s=*s1)s++; s увеличивается только при *s1!='\0'. И операция проверки совсем нелишняя, просто в твоем варианте она вставлена в for(...;*s1;...). За счет этого ты действительно можешь внутри цикла обойтись без проверки, так как у тебя внутри цикла *s1!='\0'. Тут я не прав, говоря, что это неточность. А вообще, для самого короткого (ассемблерного) варианта лучше написать в точке проверки if(*s=*s1)s++; else return; правда будет ли это считаться короче?
>> Цикл не проходит при *s='\0'. поэтому и приходится закрывать строку дополнительной операцией в конце функции.
Именно поэтому выгодней использовать while() вместо for(), также как в классическом примере копирования строки: while(*dest++=*src++);
>>Вобще, загони в компилятор и попробуй
Нехорошо отсылать к компилятору в теоретических вопросах
А теперь сравни 3 варианта: первый вариант твой, второй и третий мои. Даже при использовании более динного слова (while) мой короче на 1 символ.
for(s=s1;*s1;s++)if(*s1!=' ')*s++=*s1;*s='\0'; s=s1;while(*s)if(*s1++!=' ')if(*s=s1[-1])s++; for(s=s1;*s;)if(*s1++!=' ')if(*s=s1[-1])s++;
Мои варианты работают и с возвращаемым указателем, и без него, а в твоем сообщении вариант с возвращаемым указателем гораздо длиннее. |
|
Вернуться к началу |
|
|
Sclis Гость
|
Добавлено: Вт Апр 15 2003 14:28 Заголовок сообщения: Re: А вот как раз и нет! :) (+) |
|
|
ну хорошо, согласен на вариант for(s=s1;*s;s1++)if(*s1!=' ')*s++=*s1; согласен, что он упрощает немного код, но не s[-1]... тогда уж к индексам и Паскалю... указатели тут метод избавится от возьни с индексаи (код не эффективный будет) не стоит смешивать их. Вся ценность работы с указателями - более простой вид адресации в ассемблерном коде, а ты заставляешь машину и ту и другую адресацию использовать. Получается хуже чем любой из двух "чистых" методов эээ... "код короче на 1 символ" - аргумент не из первого десятка. "код короче вдвое" - еще можно рассматривать... "код проще и элегантней" - маячит где-то на первых позициях возвращаемый указатель должен быть не на аргумент. иначе провоцируешь на код вида if(f(s)!=s)... где-то в программе (с твоей функцией f) так не делают. просто не принято выделяй новую память под новыую переменную указатель на которую возвращаешь (вот потому второй мой вариант и получился длинее. а не из-за того, что переменные экономил) компилятор.. хм.. что же тут теоретического в споре? голимая практика мы же не "парадигмы ментальности алгоритмического подхода к восприятию" наматываем попробуй свой вариант со строковой константой . ну и ЗЫ: спор становится битвой за авторитет, а не за истину. считаю правильным остановиться на достигнутом твой ответ почитаю (если напишешь) но сам писать больше не буду |
|
Вернуться к началу |
|
|
Борис Гость
|
Добавлено: Вт Апр 15 2003 15:45 Заголовок сообщения: Ok. Дискуссия хорошо раскрасила будничный рабочий день :) (-) |
|
|
- |
|
Вернуться к началу |
|
|
|