alexanderBaranov / OOP

OOP
0 stars 0 forks source link

Замечания по программе фильтрации мата #8

Closed alexey-malov closed 8 years ago

alexey-malov commented 8 years ago
BOOST_AUTO_TEST_CASE(testStringOperations)
{
    auto badWords = GetExpression("asd,cvb,sdf,zxc,vvxzcsd.\n");

    BOOST_CHECK(badWords == vector<string>({ "asd", "cvb", "sdf", "zxc", "vvxzcsd" }));
    BOOST_CHECK_EQUAL(FilterString(badWords, "khkjhxcv zxcpipiwe asd erttwem,b") , "khkjhxcv zxcpipiwe  erttwem,b");
    BOOST_CHECK_EQUAL(FilterString(badWords, "khkjhxcv zxc asd zxcpipiwe asd erttwem,b"), "khkjhxcv   zxcpipiwe  erttwem,b");
    BOOST_CHECK_EQUAL(FilterString(badWords, "asd khkjhxcv zxc asd zxcpipiwe asd erttwem,b"), " khkjhxcv   zxcpipiwe  erttwem,b");
    BOOST_CHECK_EQUAL(FilterString(badWords, "asd, khkjhxcv zxc ,asd zxcpipiwe asd erttwem,b"), ", khkjhxcv  , zxcpipiwe  erttwem,b");
    BOOST_CHECK_EQUAL(FilterString(badWords, "asd, khkjhxcv zxc ,asd zxcpipiwe asd erttwem,b vvxzcsd"), ", khkjhxcv  , zxcpipiwe  erttwem,b ");
}

В тестах должны использовать строки, которые содержат слова реального языка, а не случайная последовательность символов.

alexey-malov commented 8 years ago

https://github.com/alexey-malov/ips-oop2015/tree/master/samples/02/Test-Driven-Development

alexey-malov commented 8 years ago

строки передавать по константной ссылке

alexey-malov commented 8 years ago

TCHAR не используй

alexey-malov commented 8 years ago
    inFile.close();

Файл открытый только для чтения можно явно не закрывать перед выходом из функции, т.к. деструктор это сделает автоматически.

alexey-malov commented 8 years ago
    vector<string> badWords;
    vector<string> values = GetExpression(contentOfInFile);
    if (values.size())
    {
        badWords.assign(values.begin(), values.end());
    }

    inFile.close();

    return badWords;

нет необходимости держать 2 вектора стоп-слов

alexey-malov commented 8 years ago
vector<string> GetExpression(string line)
{
    boost::regex expression("(\\w+)");
    vector<string> values;
    if (!boost::regex_split(back_inserter(values), line, expression))
    {
        return{};
    }

    return values;
}

regex_split вернет 0, только если ничего не вставит в values. Нет смысла в проверке Название функции не соответствует тому, что она делает

alexey-malov commented 8 years ago

dictionary.txt содержит слова, мало пригодные для практического применения

alexey-malov commented 8 years ago

Требование задания

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

строк может быть несколько

alexey-malov commented 8 years ago

Программа удаляет слова, не входящие в список стоп-слов dic1.txt

Input string: This is a fucking shit! Output string: This fucking !

Воспроизвести проблему в тесте

alexey-malov commented 8 years ago
    for_each(badWords.begin(), badWords.end(), [&inputString, &values](string value)
    {
        if (find(values.begin(), values.end(), value) != values.end())
        {
            inputString = DeleteSubstring(inputString, value);
        }
    });

for_each появился еще во времена C++'98, сейчас в использовании этого алгоритма необходимости практически нет, т.к. есть range-based for

использовать for_each больше оправдано, когда действие, совершаемое над элементами конфигурируется извне в runtime-е

alexey-malov commented 8 years ago
string Filter(const TCHAR *fileName, string inputString)
{
    auto badWords = ReadBadWordsFromFile(fileName);
    return FilterString(badWords, inputString);
}

получается, что для каждой фильтруемой строки придется считывать файл стоп-слов заново, в то время как этот список постоянный для всех вводимых пользователем строк

alexey-malov commented 8 years ago

k=0,6

alexey-malov commented 8 years ago

alexey-malov commented 8 years ago

Проблема с пересборкой не устранена

alexey-malov commented 8 years ago

После получения символа конца файла ожидать какой-либо ввод не стоит. Если перенаправить файл в stdin, то после окончания файла символы поступать не будут.

alexey-malov commented 8 years ago

Трудоемкость алгоритма: O(N^2 * M) - N - размер строки, M - количество стоп-слов в базе Можно сделать O(N*logM) (если использовать set для хранени стоп-слов), либо вообще близко к O(N) (если использовать unordered_set для хранения стоп-слов) Можно искать за логарифмическое время и в отсортированном векторе. Есть (алгоритм binary_search http://www.cplusplus.com/reference/algorithm/binary_search/)

N^2 сложность образовалась из-за

string DeleteSubstring(string& processStr, const string& delSubStr)
{
    int pos = processStr.find(delSubStr);

    while (pos != string::npos)
    {
        bool isWordOfBegStr = pos ? !isalpha((unsigned char)processStr[pos - 1]) : true;
        if (isWordOfBegStr && !isalpha((unsigned char)processStr[pos + delSubStr.length()]))
        {
            processStr.erase(pos, delSubStr.length());
        }

        pos = processStr.find(delSubStr);
    }

    return processStr;
}

Операция erase имеет линейную сложность. при этом она количество раз, линейно зависящее от длины строки.

alexey-malov commented 8 years ago

Вводить строку exit для окончания не обязательно, т.к. ввод прекратится при встрече EOF

alexey-malov commented 8 years ago
string FilterString(const vector<string>& badWords,const string& inputString)
{
    vector<string> values = ParseWordsToVector(inputString);

Переменная values не используется

alexey-malov commented 8 years ago

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

alexey-malov commented 8 years ago
    catch (exception e)
    {
        cout << e.what();
    }

Исключения следует ловить по [константной] ссылке, чтобы избежать срезки (http://rsdn.ru/forum/cpp/917744.1)