Форум программистов, компьютерный форум CyberForum.ru

Разбить введенную строку на слова - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 38, средняя оценка - 4.79
ViT(Vet@l)
27 / 26 / 2
Регистрация: 13.12.2010
Сообщений: 333
22.10.2011, 21:07     Разбить введенную строку на слова #1
Да, я знаю, что тема не нова и много раз поднималась на этом форуме.
Но не могли бы вы максимально понятно и просто реализовать эту задачу (с комментариями) - разбить введенную строку на массив слов. Пожалуйста
Просто как-то strtok не могу использовать (по причине кривизны рук).
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
22.10.2011, 21:07     Разбить введенную строку на слова
Посмотрите здесь:

C++ Разбить введенную строку на слова и выделить под каждое слово отдельный массив
C++ Распечатать введенную строку, удалив из неё слова с нечетными номерами и перевернув слова с четными номерами
C++ Разбить строку на слова
C++ Строку разбить на слова и слова запихнуть в масив char
Строка: Строку разбить на слова и слова запихнуть в массив char. C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
23.10.2011, 18:29     Разбить введенную строку на слова #2
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
// Функция разбивает строку на слова, основываясь на строке разделителей
// Принимаемые параметры:
//  str - строка, которую необходимо разбить на слова
//  delims - строку, содержащая разделители
// Возвращаемое значение:
//  динамически выделенный массив слов (заканчивающийся нулевым указателем)
char **split_string(const char *str, const char *delims)
{
    // Предварительно считаем длину входной строки
    size_t str_len = strlen(str);
 
    // Счётчик слов в предложении
    size_t words_cntr = 1;
 
    // Результирующий массив слов
    char **words;
 
    // Счётчики циклов
    size_t i, j;
    size_t w;
 
    // Считаем количество слов
    for (i = 0; i < str_len; ++i)
        // Если очередной символ входной строки совпал с одним из разделителей
        if (strchr(delims, str[i]) != NULL)
            // Увеличиваем счётчик слов
            ++words_cntr;
 
    // Выделяем память под массив слов (размером количество слов + 1 элемент для
    // нулевого указателя - конца массива слов)
    words = (char **)malloc((words_cntr + 1) * sizeof(char *));
 
    // Сразу устанавливаем ограничитель массив слов
    words[words_cntr] = NULL;
 
    // Идём по всем символам строки
    for (i = 0, w = 0; i < str_len + 1; ++i)
    {
        // j служит для указания на конеч слова, i - на начало
        // Поиск конца слова начинаем с его начала
        j = i;
 
        // Пока не достигли конца строки или не нашли разделитель
        while (str[j] != '\0' && strchr(delims, str[j]) == NULL)
            // Говорим, что очередной символ строки входит в очередное слово
            ++j;
 
        // Выделяем память под очередное слово
        words[w] = (char *)malloc((j - i + 1) * sizeof(char));
 
        // Копируем слово в выделенную память
        strncpy(words[w], str + i, j - i);
        // Ограничиваем слово нуль-терминатором
        words[w++][j - i] = '\0';
 
        // Продолжаем поиск следующего слова с конца только что обработанного
        i = j;
    }
 
    // Возвращаем сформированный массив слов
    return words;
}
 
// Функция просто очищает память, выделенную под массив слов
void destroy_words(char **words)
{
    size_t i = 1;
 
    while (words[i - 1] != NULL)
        free(words[i++]);
 
    free(words);
}
 
int main(void)
{
    const char *str = "aaa bbb cc eeee d";
    const char *delims = " ";
 
    char **words = split_string(str, delims);
    
    size_t i;
 
    for (i = 0; words[i] != NULL; ++i)
        printf("%s\n", words[i]);
 
    destroy_words(words);
 
    return 0;
}
ViT(Vet@l)
27 / 26 / 2
Регистрация: 13.12.2010
Сообщений: 333
24.10.2011, 17:53  [ТС]     Разбить введенную строку на слова #3
Почему тогда выбивает ошибку \1\main.cpp||In function 'int main()':|
\1\main.cpp|93|error: 'string' was not declared in this scope|


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
 
// Функция разбивает строку на слова, основываясь на строке разделителей
// Принимаемые параметры:
//  str - строка, которую необходимо разбить на слова
//  delims - строку, содержащая разделители
// Возвращаемое значение:
//  динамически выделенный массив слов (заканчивающийся нулевым указателем)
char **split_string(const char *str, const char *delims)
{
    // Предварительно считаем длину входной строки
    size_t str_len = strlen(str);
 
    // Счётчик слов в предложении
    size_t words_cntr = 1;
 
    // Результирующий массив слов
    char **words;
 
    // Счётчики циклов
    size_t i, j;
    size_t w;
 
    // Считаем количество слов
    for (i = 0; i < str_len; ++i)
        // Если очередной символ входной строки совпал с одним из разделителей
        if (strchr(delims, str[i]) != NULL)
            // Увеличиваем счётчик слов
            ++words_cntr;
 
    // Выделяем память под массив слов (размером количество слов + 1 элемент для
    // нулевого указателя - конца массива слов)
    words = (char **)malloc((words_cntr + 1) * sizeof(char *));
 
    // Сразу устанавливаем ограничитель массив слов
    words[words_cntr] = NULL;
 
    // Идём по всем символам строки
    for (i = 0, w = 0; i < str_len + 1; ++i)
    {
        // j служит для указания на конеч слова, i - на начало
        // Поиск конца слова начинаем с его начала
        j = i;
 
        // Пока не достигли конца строки или не нашли разделитель
        while (str[j] != '\0' && strchr(delims, str[j]) == NULL)
            // Говорим, что очередной символ строки входит в очередное слово
            ++j;
 
        // Выделяем память под очередное слово
        words[w] = (char *)malloc((j - i + 1) * sizeof(char));
 
        // Копируем слово в выделенную память
        strncpy(words[w], str + i, j - i);
        // Ограничиваем слово нуль-терминатором
        words[w++][j - i] = '\0';
 
        // Продолжаем поиск следующего слова с конца только что обработанного
        i = j;
    }
 
    // Возвращаем сформированный массив слов
    return words;
}
 
// Функция просто очищает память, выделенную под массив слов
void destroy_words(char **words)
{
    size_t i = 1;
 
    while (words[i - 1] != NULL)
        free(words[i++]);
 
    free(words);
}
 
int main(void)
{
    const char *str = "aaa bbb cc eeee d";
    const char *delims = " ";
 
    char **words = split_string(str, delims);
 
    size_t i;
 
    for (i = 0; words[i] != NULL; ++i)
        printf("%s\n", words[i]);
 
    string subject[5]={"I","he","she","it","they"};
    string predicate[5]={"go","stand","fly","say","run"};
    string attribute[5]={"quick", "nice", "slow", "ugly", "normal"};
    string str_1, str_2, str_3;
     for(int i = 0; i < 5; i++){
            if(words[0] != subject[i]){
                if(words[0] == predicate[i])
                    str_2 = words[0];
                if(words[0] == attribute[i])
                    str_3 = words[0];
            }
            else{
                str_1 = words[0];
            }
        }
 
        for(int i = 0; i < 5; i++){
            if(words[1] != predicate[i]){
                if(words[1] == subject[i])
                    str_1 = words[1];
                if(words[1] == attribute[i])
                    str_3 = words[1];
            }
            else{
                str_2 = words[1];
            }
        }
 
 
        for(int i = 0; i < 5; i++){
            if(words[2] != attribute[i]){
                if(words[2] == subject[i])
                    str_1 = words[2];
                if(words[2] == predicate[i])
                    str_2 = words[2];
            }
            else{
                str_3 = words[2];
            }
        }
 
        cout << str_1 << " " << str_2 << " " << str_3;
 
 
 
    cin.get();
 
 
    destroy_words(words);
 
    return 0;
}
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
24.10.2011, 20:18     Разбить введенную строку на слова #4
ViT(Vet@l), подключите заголовочный файл string и используйте std::string.
ViT(Vet@l)
27 / 26 / 2
Регистрация: 13.12.2010
Сообщений: 333
24.10.2011, 21:50  [ТС]     Разбить введенную строку на слова #5
silent_1991, м-да, что-то я сегодня не внимательный
(конечно жестокий черновик, но такое не заметить - видимо сильно устал)
Olga_
 Аватар для Olga_
840 / 182 / 16
Регистрация: 01.08.2011
Сообщений: 502
24.10.2011, 22:06     Разбить введенную строку на слова #6
silent_1991, есть алгоритм, который устроен хитрее Вашего (разбиение строки на слова), поэтому работает в разы быстрее:
http://www.cyberforum.ru/showthread.php?p=1880997
В нем нет долгих функций strchr()
Плюс к тому в нем нет того недостатка, который есть в функции strtok(), а именно, замена символов разделителей нуль-символом, то есть если строка нам пригодится, то она будет испорчена.
Алгоритм взят из прилагаемой книги в том посте.
Сложность этого алгоритма O(m+n), где m - длина строки разделителей, n - длина строки-предложения. А если использовать функцию strchr (как у Вас), то сложность алгоритма будет O(m*n). Видите какая разница огромная.

Цитата Сообщение от ViT(Vet@l) Посмотреть сообщение
Просто как-то strtok не могу использовать.
И не надо, зачем, она портит предложение, меняет в нем символы, есть более быстрый и оптимальный вариант, о чем выше написано.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
24.10.2011, 22:13     Разбить введенную строку на слова #7
Olga_, я что, где-то претендовал на оригинальность и скорость? Если так - ссылку в студию. Иначе - чем плох альтернативный вариант решения (пусть даже менее быстрый)?
Olga_
 Аватар для Olga_
840 / 182 / 16
Регистрация: 01.08.2011
Сообщений: 502
24.10.2011, 22:15     Разбить введенную строку на слова #8
Цитата Сообщение от silent_1991 Посмотреть сообщение
Olga_, я что, где-то претендовал на оригинальность и скорость? Если так - ссылку в студию. Иначе - чем плох альтернативный вариант решения (пусть даже менее быстрый)?
Я ничего не имею против Вашего алгоритма. Он мне даже понравился Просто хочется поделиться идеей более быстрых алгоритмов этого типа. У Вас хороший алгоритм, просто его можно значительно ускорить.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
24.10.2011, 22:20     Разбить введенную строку на слова #9
Olga_, тут стандартная дилемма - скорость или память. В вашем алгоритме скорость достигается за счёт дополнительной памяти - все результаты strchr уже как-бы высчитаны заранее, у меня же эти значения каждый раз вычисляются заново.
Хотя согласен - дополнительная память здесь мизерная (всего каких-то 256 байт), однако если брать в расчёт какие-нибудь микроконтроллеры, то там не то что каждый байт, каждый бит на счету, зато вычислительных мощностей хватает с лихвой. Поэтому тут стоит делать выбор по ситуации.

Добавлено через 1 минуту
Ну а мой алгоритм - решение в лоб, так что его даже обсуждать не следует, ИМХО)))
ViT(Vet@l)
27 / 26 / 2
Регистрация: 13.12.2010
Сообщений: 333
24.10.2011, 22:20  [ТС]     Разбить введенную строку на слова #10
Olga_, спасибо, завтра почитаю
Olga_
 Аватар для Olga_
840 / 182 / 16
Регистрация: 01.08.2011
Сообщений: 502
24.10.2011, 22:21     Разбить введенную строку на слова #11
Пока мы рассматриваем обычные компьютеры, поэтому 256 байт это мизер, как Вы правильно выразились. А ускорение при этом немалое. А если строка разделителей не меняется, то массив flag только один раз заполняется. И очень важно информацию очень быстро уметь обрабатывать
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
24.10.2011, 22:23     Разбить введенную строку на слова #12
ViT(Vet@l), кстати, скажи вы, что пишите на C++, задача решалась бы в 3 строки. Через стрингстримы.

Цитата Сообщение от Olga_ Посмотреть сообщение
Пока мы рассматриваем обычные компьютеры
Разумеется, но должен же я был привести хоть какой-то аргумент в свою пользу
Olga_
 Аватар для Olga_
840 / 182 / 16
Регистрация: 01.08.2011
Сообщений: 502
24.10.2011, 22:27     Разбить введенную строку на слова #13
silent_1991, у Вас очень хороший алгоритм, просто раз поднялась тема про строки, то вот, предлагаю и такой вариант Еще согласитесь, что неприятный недостаток функции strtok в замене символов, поэтому часто полезнее вовсе без нее обходиться.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
24.10.2011, 22:34     Разбить введенную строку на слова #14
Olga_, не, я вполне серьёзно говорил, что мой алгоритм даже обсуждать не следует, это не свойственный мне во всех других ситуациях сарказм . Просто это ведь действительно решение в лоб, практически бездумное.
strtok - сам не люблю, то, что она портит строку, большой минус. Поэтому чрезвычайно редко её использую.
Olga_
 Аватар для Olga_
840 / 182 / 16
Регистрация: 01.08.2011
Сообщений: 502
24.10.2011, 22:39     Разбить введенную строку на слова #15
Цитата Сообщение от silent_1991 Посмотреть сообщение
strtok - сам не люблю, то, что она портит строку, большой минус. Поэтому чрезвычайно редко её использую.
Ура, есть единомышленники!!!))) я вот тоже избегаю эту функцию. Мне кажется, что тот алгоритм, на который сделала ссылку в #6, уже имеет минимальную сложность из всех возможных, очень быстрый алгоритм.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.10.2011, 23:31     Разбить введенную строку на слова
Еще ссылки по теме:

C++ Разбить строку на слова
Разбить строку на слова C++
Разбить строку на слова, добавить эти слова в массив строк C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
ViT(Vet@l)
27 / 26 / 2
Регистрация: 13.12.2010
Сообщений: 333
24.10.2011, 23:31  [ТС]     Разбить введенную строку на слова #16
silent_1991, в код приведенный в #3 не смотрите
Есть 3 массива: подлежащие[5], сказуемые[5], определения[5] (содержимое фиксировано).
Вводится текст - в нем должны идти по порядку: 1)подлежащии 2)сказуемое 3)определение.
Если порядок не соблюдается - сделать так как надо. Если слово повторяется, то написать "слово СЛОВО повторяется"
Вот и пытаюсь сделать сам, но получается много хлама
Yandex
Объявления
24.10.2011, 23:31     Разбить введенную строку на слова
Ответ Создать тему
Опции темы

Текущее время: 02:38. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru