Как удалить согласные из строки?

Вот мой код:

#include <iostream>
#include <string>
#include<bits/stdc++.h>
using namespace std;

int main() 
{
    int n;
    cin >> n;

    while(n--)
    {
        string str;
        char a[] = {'a','e','i','o','u','A','E','I','O','U'};
        getline(cin, str);

        for(int i=0 ;i<str.length(); i++)
        {
            for(int j=0; j<10; j++)
            {
                if(str[i]==a[j])
                {
                    cout << str[i];
                }
            }
        }
        cout << "\n"; 
    }
    return 0;
}

Тестовые случаи:

HmlMqPhBfaVokhR 
wdTSFuI 
IvfHOSNv 

Я ничего не удаляю, но печатаю только гласные. Но некоторые тесты не прошли. Возможно, этот код не работает в нескольких тестовых случаях.


person Priyam Rajvanshi    schedule 06.06.2018    source источник
comment
а) вы ничего не удаляете из строки б) каковы тестовые примеры? в) вы должны включить <string>, а не <string.h>   -  person 463035818_is_not_a_number    schedule 06.06.2018
comment
Что за описание и в чем проблема?   -  person rsy56640    schedule 06.06.2018
comment
Одна ошибка, нужно ignore() после cin>>n;, иначе getline(cin, str); ничего не получит. и это не то, что вы должны делать : #include<bits/stdc++.h>   -  person JeJo    schedule 06.06.2018
comment
Примеры тестов: HmlMqPhBfaVokhR wdTSFuI IvfHOSNv Я обновил ‹string.h› до ‹string›, но проблема не решена. Я ничего не удаляю, но печатаю только гласные.   -  person Priyam Rajvanshi    schedule 06.06.2018
comment
@PriyamRajvanshi Редактируйте свой вопрос с тестовыми примерами, а не в комментариях.   -  person JeJo    schedule 06.06.2018
comment
Кстати, в целом ваш минимальный воспроизводимый пример будет более автономным, если вы поместите ввод, жестко закодированный в код, вместо использования пользовательского ввода , с другой стороны, может быть, ошибка заключается в том, как вы принимаете пользовательский ввод, и, с другой стороны, вам лучше в любом случае разделить ввод и логику (т.е. сделать функцию remove_consonants, которая принимает string в качестве параметра и может быть протестирована независимо откуда эта строка)   -  person 463035818_is_not_a_number    schedule 06.06.2018
comment
@JeJo, не могли бы вы предоставить мне код, пожалуйста?   -  person Priyam Rajvanshi    schedule 06.06.2018
comment
Проверьте это Использование getline(cin, s) после cin   -  person acraig5075    schedule 06.06.2018
comment
Теперь вы действительно хотите удалить гласные или просто хотите распечатать ввод без них?   -  person Aconcagua    schedule 06.06.2018
comment
Вам нужно показать тесты (возможно, только неудачные тесты). Без этого ваш вопрос неполный.   -  person Toby Speight    schedule 06.06.2018


Ответы (3)


Попробуйте это для правильной консоли в< /эм> :

int main()
{
    int n;
    std::cin >> n;
    std::cin.ignore();   // fix
    /* remaining code */
    return 0;
}

> Чтобы найти гласные в строке

Способ поиска гласных в строке заключается в использовании std::binary_search каждого символа данной строки в таблице гласных.

  1. Создайте отсортированный массив из char всех гласных (т. е. массив гласных).
  2. Для каждого char входной строки std::binary_search в массиве vowels .
  3. Если std::binary_search возвращает true (это означает, что char является гласной), выведите char строки.

Ниже приведен пример кода! (Посмотреть онлайн)

#include <iostream>
#include <string>
#include <algorithm> // std::for_each, std::binary_search, std::sort
#include <array>     // std::array

int main()
{
    std::array<char, 10> a{ 'a','e','i','o','u','A','E','I','O','U' };
    std::sort(a.begin(), a.end()); // need sorted array for std::binary_search

    const std::string str{ "HmlMqPhBfaVokhR wdTSFuI IvfHOSNv" };
    std::for_each(str.cbegin(), str.cend(), [&](const char str_char)
    {
        if (std::binary_search(a.cbegin(), a.cend(), str_char))
            std::cout << str_char << " ";
    });
    return 0;
}

Вывод:

a o u I I O

> Чтобы удалить гласные из строки

Используйте идиому стереть-удалить следующим образом. (до c++ 17).

  1. Создайте отсортированный массив из char всех гласных (т. е. массив гласных).
  2. Используя std::remove_if, соберите итераторы, указывающие на символы, которые являются гласными. Лямбда-функцию можно использовать в качестве предиката для std::remove_if, где std::binary_search используется для проверки наличия char в строке в массиве гласных.
  3. Используя std::string::erase, сотрите все собранные символы (например, гласные) из нить.

Ниже приведен пример кода! (Посмотреть онлайн)

#include <iostream>
#include <string>
#include <algorithm> // std::sort, std::binary_search, std::remove_if
#include <array>     // std::array

int main()
{
    std::array<char, 10> a{ 'a','e','i','o','u','A','E','I','O','U' };
    std::sort(a.begin(), a.end()); // need sorted array for std::binary_search

    std::string str{ "Hello World" };
    // lambda(predicate) to check the `char` in the string exist in vowels array
    const auto predicate = [&a](const char str_char) -> bool { 
        return std::binary_search(a.cbegin(), a.cend(), str_char);
    };
    // collect the vowels
    const auto vowelsToRemove = std::remove_if(str.begin(), str.end(), predicate);
    // erase the collected vowels using std::string::erase
    str.erase(vowelsToRemove, str.end());

    std::cout << str << "\n";
    return 0;
}

Вывод:

Hll Wrld

Поскольку c++20 можно использовать std::erase_if для этого, что будет менее подвержен ошибкам, чем приведенный выше. (Посмотрите онлайн в прямом эфире, используя GCC 9.2)

#include <iostream>
#include <string>    // std::string, std::erase_if
#include <array>     // std::array

int main()
{
    std::array<char, 10> a{ 'a','e','i','o','u','A','E','I','O','U' };
    std::sort(a.begin(), a.end()); // need sorted array for std::binary_search

    std::string str{ "Hello World" };
    // lambda(predicate) to check the `char` in the string exist in vowels array
    const auto predicate = [&a](const char str_char) -> bool { 
        return std::binary_search(a.cbegin(), a.cend(), str_char);
    };

    std::erase_if(str, predicate); // simply erase

    std::cout << str << "\n";
    return 0;
}

> Чтобы удалить согласные из строки

Чтобы удалить согласные из данной строки, в приведенном выше predicate инвертируйте результат std::binary_search. (Посмотреть в прямом эфире)

const auto predicate = [&a](const char str_char) -> bool { 
    return !std::binary_search(a.cbegin(), a.cend(), str_char);
    //     ^^ --> negate the return
};

Как примечания,

person JeJo    schedule 06.06.2018
comment
Откуда вы знаете, каков «порядок возрастания» для вектора символов? И откуда вы знаете, что бинарный поиск будет быстрее, чем линейный поиск для такого короткого списка символов? - person Pete Becker; 06.06.2018
comment
@PeteBecker вы согласны O(log10)O(10)? если так, бинарный поиск лучше всегда. Однако для небольшого массива мы также можем выполнять линейный поиск, что в конечном итоге не будет большой разницей в производительности. - person JeJo; 06.06.2018
comment
Если ввод достаточно мал, накладные расходы на сортировку могут даже поглотить все небольшое преимущество, которое, возможно, еще осталось... Предположим, проблема слишком проста для такого сложного подхода (но мне это нравится...). - person Aconcagua; 06.06.2018
comment
@Aconcagua: что касается std::sort(), это правда, что ты сказал. Он также мог бы использовать сортировку перед циклом, чтобы каждый раз можно было избежать сортировки. Однако я лишь обобщил ситуацию, которая будет применима и к другим символам, не являющимся гласными. Кроме того, бинарный поиск — моя привычка. Однако я нашел strchr также хорошим подходом, так как массив небольшой. - person JeJo; 06.06.2018
comment
@JeJo - бинарный поиск лучше подходит для больших входных данных. Асимптотическая сложность связана с асимптотами; это не абсолютная мера производительности. - person Pete Becker; 06.06.2018

Помимо уже решенной проблемы std::getline:

for(int i=0 ;i<str.length(); i++)
{
    for(int j=0; j<10; j++)
    {
        if(str[i] == a[j])
        {
            // this is the one you do NOT want to print...
            // cout<<str[i];
            // skip instead:
            goto SKIP;
        }
    }
    std::cout << str[i]; // output the one NOT skipped...
    SKIP: (void)0;
}

Хорошо, не хочу начинать обсуждение использования goto, есть много способов избежать этого, например. грамм. путем упаковки внутреннего цикла for в отдельную (встроенную) функцию. Однако вам может быть проще, поскольку такая функция уже существует; код становится еще проще с циклом for на основе диапазона:

for(auto c : str)
{
    if(!strchr("aeiouAEIOU", c))
    {
        std::cout << c;
    }
}

strchr (из cstring) возвращает указатель на первый символ в строке, равный ссылочному символу, или nullptr, если он не найден...

Чтобы действительно удалить гласные из строки современным способом C++, рассмотрите следующее:

str.erase(std::remove_if(
        str.begin(), str.end(),
        [](char c) { return strchr("aeiouAEIOU", c) != nullptr; }
    ), str.end());
person Aconcagua    schedule 06.06.2018

Ваш код, вероятно, должен выглядеть так (см. встроенные комментарии):

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

int main() {
    string vowels = "aeiouAEIOU";

    int n;
    cin>>n; // assume this stands for line count

    while(n-- >= 0)
    {
        string str, result;
        getline(cin, str);

        for(int i=0 ;i<str.length(); i++)
        {
            if (vowels.find(str[i]) != std::string::npos)
                result += str[i];   // add character to result if it is not consonant
        }
        cout<<result<<"\n"; // print result
    }

    return 0;
}
person zhm    schedule 06.06.2018
comment
Этот код не решает проблему. Все, что он делает, это усложняет код; он производит точно такой же результат. - person Pete Becker; 06.06.2018
comment
@PeteBecker OP на самом деле плохо объяснил проблему. Я понял, что количество строк на одну меньше, чем должно быть. Не уверен, что это проблема. - person zhm; 06.06.2018