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

В своей программе я проверяю всю cstring, если обнаружены какие-либо пробелы или знаки препинания, просто добавляю пустой символ в это место, но компилятор выдает мне ошибку: пустая символьная константа.

Пожалуйста, помогите мне, в моем цикле я проверяю вот так

if(ispunct(str1[start])) {
    str1[start]=''; // << empty character constant. 
}
if(isspace(str1[start])) {
    str1[start]=''; // << empty character constant. 
}

Вот где мои ошибки, пожалуйста, поправьте меня.

например, слово str,, ing, вывод должно быть string.


person user3215228    schedule 13.02.2014    source источник
comment
Что такое пустой символ?   -  person Angew is no longer proud of SO    schedule 13.02.2014
comment
@Angew А удалили;) ...   -  person πάντα ῥεῖ    schedule 13.02.2014
comment
@ jrd1 Нет, это не дурак (особенно не касательно принятого там ответа)! Нет необходимости в «сжатии» или динамическом изменении размера массива, см. Мой ответ и другие комментарии ниже ...   -  person πάντα ῥεῖ    schedule 14.02.2014
comment
@ user3215228 Обратите внимание на мои дополнительные рекомендации по реальным c ++ реализациям.   -  person πάντα ῥεῖ    schedule 14.02.2014


Ответы (5)


Попробуйте это (как вы явно просили cstring):

char str1[100] = "str,, ing";

if(ispunct(str1[start]) || isspace(str1[start])) {
    strncpy(str1 + start, str1 + start + 1, strlen(str1) - start + 1);
}

Что ж, если сделать это на чистом языке c, там являются более эффективными решениями (подробности см. в ответе @MichaelPlotke).

Но поскольку вы также явно просите c ++, Я бы порекомендовал следующее решение:

Примечание, вы можете использовать стандартные алгоритмы C ++. для "простых" символьных массивов в стиле c. Вам просто нужно поместить свои условия предиката для удаления в небольшой вспомогательный функтор и использовать его с алгоритмом std::remove_if():

struct is_char_category_in_question {
    bool operator()(const char& c) const;
};

А потом используйте это как:

#include <string>
#include <algorithm>
#include <iostream>
#include <cctype>
#include <cstring>

// Best chance to have the predicate elided to be inlined, when writing 
// the functor like this:
struct is_char_category_in_question {
    bool operator()(const char& c) const {
        return std::ispunct(c) || std::isspace(c);
    }
};

int main() {
    static char str1[100] = "str,, ing";
    size_t size = strlen(str1);

    // Using std::remove_if() is likely to provide the best balance from perfor-
    // mance  and code size efficiency you can expect from your compiler 
    // implementation.
    std::remove_if(&str1[0], &str1[size + 1], is_char_category_in_question());

    // Regarding specification of the range definitions end of the above state-
    // ment, note we have to add 1 to the strlen() calculated size, to catch the 
    // closing `\0` character of the c-style string being copied correctly and
    // terminate the result as well!

    std::cout << str1 << endl; // Prints: string
}

См. Также этот компилируемый и рабочий образец здесь.

person Community    schedule 13.02.2014
comment
Я не голосующий против, но могу предположить, что это может иметь какое-то отношение к следующему ответу: stackoverflow.com/a/6987247/ 866930. - person jrd1; 13.02.2014
comment
Что плохого в использовании strncpy () в c ++ ?? У меня много ситуаций, когда я просто не могу позволить себе пользоваться std::string ... - person πάντα ῥεῖ; 14.02.2014
comment
Использование remove_if в C-String полностью неверно, поскольку remove_if не удаляет символы из статически выделенного массива, а только сохраняет содержимое в памяти без замены в оставшейся части строки. - person jrd1; 14.02.2014
comment
@ jrd1 По крайней мере, это работает нормально ?? ИМХО, неважно, статически ли распределен массив или нет (вы имели в виду константные входы ??)! - person πάντα ῥεῖ; 14.02.2014
comment
См. Это: stackoverflow.com/a/19139765/866930 - person jrd1; 14.02.2014
comment
@ jrd1 Хорошее исследование, но не совсем актуально для того, о чем здесь просят, нет необходимости «сжимать» что-либо. Если он имеет фиксированный размер, он имеет фиксированный размер, и ничто в моем ответе никогда не будет действовать вне границ массива в любое время ... - person πάντα ῥεῖ; 14.02.2014
comment
Раньше не видел remove_if. Выглядит круто. Тем не менее, я нахожу свой ответ в стиле c более читабельным. - person Michael Plotke; 14.02.2014
comment
@MichaelPlotke Какой код из одной строки может быть более читаемым, чем remove_if() ?? Поведение довольно хорошо определено, и вы можете легко найти ссылку на него. - person πάντα ῥεῖ; 14.02.2014
comment
@ πάνταῥεῖ По общему признанию, remove_if интуитивно назван и, как вы говорите, задокументирован. С другой стороны, C ++ скрывает вещи таким образом, что их трудно понять. Что творится под капотом? Ничего хорошего (на основе сравнения эффективности). - person Michael Plotke; 14.02.2014
comment
@MichaelPlotke Обратитесь к моему другому комментарию, пожалуйста ... - person πάντα ῥεῖ; 14.02.2014
comment
Я не получил отрицательных голосов за этот ответ! Может быть, так. можете объяснить или предложить улучшения ?? - person πάντα ῥεῖ; 14.02.2014

Не бывает пустого символа.

Если вы имеете в виду пробел, измените '' на ' ' (с пробелом в нем).

Если вы имеете в виду NUL, измените его на '\0'.

person Paul    schedule 13.02.2014
comment
Нет, я не имею в виду нулевой символ, я просто хочу, чтобы пробелы и знаки препинания были заменены пустыми пробелами. - person user3215228; 13.02.2014
comment
@ user3215228 Что такое пустое место? Вы имеете в виду космический персонаж? Или вы действительно хотите удалить пробелы и знаки препинания из строки? - person Angew is no longer proud of SO; 13.02.2014
comment
Вы имеете в виду, что хотите удалить этих персонажей? Вы не можете сделать этого, присвоив им значение. Вам нужно сдвинуть все символы в строке после этой позиции назад на одну позицию или что-то в этом роде. - person Paul; 13.02.2014
comment
например, слово str ,, ing, вывод должен быть строкой - person user3215228; 13.02.2014
comment
@ user3215228 Как упоминал paulpro, вы хотите удалить символы. Это совершенно другая операция, я рекомендую использовать для этого std::string, в противном случае скопируйте оставшуюся часть строки в то место, где вы нашли один из ваших персонажей. - person πάντα ῥεῖ; 13.02.2014

Изменить: ответ больше не актуален теперь, когда OP отредактировал вопрос. Оставляем ради потомства.

Если вы хотите добавить нулевой символ, используйте '\ 0'. Если вы хотите использовать другой символ, используйте для этого соответствующий символ. Вы не можете ничего назначить. Это бессмысленно. Это как сказать

int myHexInt = 0x;

or

long long myIndeger = L;

Компилятор выдаст ошибку. Вставьте то значение, которое вы хотели. В случае с символом это значение от 0 до 255.

person m24p    schedule 13.02.2014
comment
Нет, я не имею в виду нулевой символ, я просто хочу, чтобы пробелы и знаки препинания были заменены пустыми пробелами. - person user3215228; 13.02.2014
comment
Хорошо, тогда используйте пробел. str1[start]=' '; Только не пытайтесь присвоить персонажа ничему. Это все равно что сказать int x = ; и надеяться, что он скомпилируется. - person m24p; 13.02.2014
comment
@ m24p OP хочет заменить пробел символом пробелом ?? - person πάντα ῥεῖ; 13.02.2014
comment
Я думал, что функция isspace проверяет все типы пробелов, например символы табуляции и т. Д. OP с тех пор прояснил, что реальный вопрос должен заключаться в том, как удалить символы. - person m24p; 13.02.2014
comment
@ m24p Я уже уточнял, но не важно ... - person πάντα ῥεῖ; 13.02.2014

ОБНОВИТЬ:

Из редактирования вопроса OP очевидно, что он / она хотел обрезать строку знаков препинания и пробелов.

Как подробно описано в отмеченном возможном дубликате, один из способов - использовать remove_copy_if:

string test = "THisisa test;;';';';";
string temp, finalresult;

remove_copy_if(test.begin(), test.end(), std::back_inserter(temp), ptr_fun<int, int>(&ispunct));
remove_copy_if(temp.begin(), temp.end(), std::back_inserter(finalresult), ptr_fun<int, int>(&isspace));

ОРИГИНАЛ

Изучив ваш вопрос, замена пробелов пробелами является избыточной, поэтому вам действительно нужно выяснить, как заменить знаки препинания пробелами. Вы можете сделать это, используя функцию сравнения (обернув std::ispunct) в тандеме с std::replace_if из STL:

#include <string>
#include <algorithm>
#include <iostream>
#include <cctype>
using namespace std;

bool is_punct(const char& c) {
    return ispunct(c);
}

int main() {
    string test = "THisisa test;;';';';";
    char test2[] = "THisisa test;;';';'; another";

    size_t size = sizeof(test2)/sizeof(test2[0]);

    replace_if(test.begin(), test.end(), is_punct, ' ');//for C++ strings
    replace_if(&test2[0], &test2[size-1], is_punct, ' ');//for c-strings

    cout << test << endl;
    cout << test2 << endl;
}

Это выводит:

THisisa test
THisisa test         another
person jrd1    schedule 13.02.2014
comment
Было ли что-то, что можно было бы улучшить для того, кто проголосовал против? Если так, я буду рад любым отзывам. - person jrd1; 13.02.2014
comment
@ πάνταῥεῖ: Нет проблем. Это честная ошибка: такие вещи действительно случаются. - person jrd1; 13.02.2014
comment
'Голосовавшему против ...' К сожалению, это не ошибка: вопрос требует удаления этих символов, а не замены их пробелами ('\0x32')! Вы бы лучше упомянули std::remove_if ... - person πάντα ῥεῖ; 14.02.2014
comment
@ πάνταῥεῖ: Я только сейчас увидел эту правку: я работаю над этим. Спасибо! - person jrd1; 14.02.2014
comment
Это не дубликат этого вопроса, по крайней мере, принятый ответ не применим ... - person πάντα ῥεῖ; 14.02.2014

Поскольку мне не нравится принятый ответ, вот мой:

#include <stdio.h>
#include <string.h>
#include <cctype>

int main() {
    char str[100] = "str,, ing";
    int bad = 0;
    int cur = 0;
    while (str[cur] != '\0') {
        if (bad < cur && !ispunct(str[cur]) && !isspace(str[cur])) {
                str[bad] = str[cur];
        }
        if (ispunct(str[cur]) || isspace(str[cur])) {
            cur++;
        }
        else {
            cur++;
            bad++;
        }
    }
    str[bad] = '\0';
    fprintf(stdout, "cur = %d; bad = %d; str = %s\n", cur, bad, str);
    return 0;
}

Какие выходы cur = 18; bad = 14; str = string

У этого есть преимущество в том, что он более эффективен и более читабелен, хм, ну, в стиле, который мне больше нравится (см. Комментарии для продолжительных дебатов / объяснений).

person Michael Plotke    schedule 13.02.2014
comment
Да, после небольшого исправления кода он работает нормально и более эффективен (по крайней мере, по сравнению с версией strncpy()) . Было бы неплохо получить подтверждение, что remove_if() образец действительно менее эффективен, чем то, что дано в вашем ответе. - person πάντα ῥεῖ; 14.02.2014
comment
@ πάνταῥεῖ Да, ваш код действительно значительно менее эффективен. Примерно в 16 раз менее производительный (на моей машине). Я только что сравнивал каждую из них. Не стесняйтесь дублировать мои выводы. - person Michael Plotke; 14.02.2014
comment
Значит, хорошее замечание! Не могли бы вы подробнее рассказать о своих методах тестирования? Я обеспокоен тем, что remove_if() можно легко реализовать таким же образом, как и вы, и я обычно предполагаю, что стандартные реализации настолько эффективны, насколько это возможно, чтобы охватить применимые варианты использования. К сожалению, это может быть неверно для всех компиляторов и реализаций стандартной библиотеки C ++! - person πάντα ῥεῖ; 14.02.2014
comment
Тест просто использует метод основного ответа для определения времени. цикл из 10000000 итераций каждого метода со строкой str ,, ing. - person Michael Plotke; 14.02.2014
comment
Чтобы процитировать ссылку на remove_if: 'Удаление выполняется путем сдвига элементов в диапазоне таким образом, что элементы, которые должны быть удалены, перезаписываются. ' Это позволяет мне предположить, что правильная реализация должна следовать вашему алгоритму ... - person πάντα ῥεῖ; 14.02.2014
comment
Хм, в настоящее время я пытаюсь воспроизвести тесты производительности, предложенные вами, на ideone. Кажется, я застрял на этом :( ... Не могли бы вы прояснить свой набор инструментов, используемый для эталонный тест (я боюсь, что это проблема, связанная с конкретной инструментальной цепочкой, как уже упоминалось)? (В моих предыдущих комментариях акцент должен был быть на смещении BTW) - person πάντα ῥεῖ; 14.02.2014
comment
Linux 3.12.9-2-ARCH # 1 SMP PREEMPT Пт 31 января 10:22:54 CET 2014 x86_64 GNU / Linux | g ++ (GCC) 4.8.2 20140206 (предварительная версия) | Хотя gettimeofday - не лучший метод тестирования производительности, он довольно точен и прост в реализации. У меня никогда не было с этим проблем ... - person Michael Plotke; 14.02.2014
comment
В ПОРЯДКЕ! Мне только что удалось скомпилировать ваши тесты на ideone (немного странно, необходимо включить time.h и sys\time.h :(): remove_if () образец, c -style while loop sample, и я должен признать, что ваши выводы о недостатках производительности кажутся правильными. Это действительно заставляет меня беспокоиться о реализации GCC (я использовал старую версию для примеров, но я не думаю, что это имеет большое значение) .Может быть хорошим поводом задать еще один вопрос по этому поводу! - person πάντα ῥεῖ; 14.02.2014
comment
Это меня сильно расслабляет: std :: remove_if Реализация GCC неэффективна? - person πάντα ῥεῖ; 14.02.2014
comment
Так что никаких реальных улучшений от вашего решения, извините ... - person πάντα ῥεῖ; 14.02.2014
comment
Подтвержденный. Мне все еще больше нравится код в стиле c, но это только я. Спасибо, что нашли время разобраться в этом. - person Michael Plotke; 14.02.2014
comment
«Спасибо, что нашли время, чтобы разобраться в этом». De nada! Я сам был просто любопытен (и немного обеспокоен) ... Мой обычный опыт: вы не можете легко обеспечить лучшую эффективность по сравнению с реализациями стандартной библиотеки C ++. Но, как мы видим (из моего плохого бывшего образца), вы можете использовать их явно неправильно :( ... - person πάντα ῥεῖ; 14.02.2014
comment
FWIW мое решение в стиле C будет похоже на char *dst = str, *src = str; while (*src) { if !ispunct(*src) && !isspace(*src) { *dst++ = *src; } ++src; } *dst = 0;. И это почти именно то, что remove_if будет делать если вы можете правильно встроить все, за исключением того, что, конечно, он не знает о строках с нулевым завершением. - person Steve Jessop; 14.02.2014