C++ для начинающих. Строки. Разбить строку на слова

Начинающим программистам полезно поупражняться в решении задачи разбиения предложения на слова.
К решению задачи разбиения предложений на слова могут быть разные требования, в которых, например, могут быть требования запрета использования функции strtok и ей подобных, запрет на использование строковых потоков и другие запреты. Эти ограничения обусловлены тем, что дающий такие задания хочет научить своего студента немного работать с текстом.
Но пока что отложим решения с ограничениями, будем использовать наиболее простые способы:
В простейшем случае в предложении все слова написаны полностью и в учебных целях не нужно предусматривать чуть более сложные случаи, чем простые. Например, если в предложении слова объединяются апострофом, как в английском языке: I’m, то это два слова: I am. Новичкам не нужно на таких моментах запариваться, и имеет смысл выдавать два слова как есть, т. е. слово I и слово m. Что нашли в тексте, о том и сказали, это нормально для новичков.
Самый простой и короткий способ деления предложений на слова — это использование строковых потоков.
Современный стиль:

Стиль эпохи динозавров:

Это самый быстрый для программиста способ написания кода, разбивающего строку на слова, например, для подсчёта количества слов в строке. Сейчас я вывожу слова, но это чтобы было вам видно, что для обработки отдельных слов в дальнейшем требуются дополнительные затраты времени на написание кода, ведь многие ненужные слову символы прилипают к словам, нужно их подчищать.
Принцип работы очень прост: внести в поток, забирать из потока. При отборе у потока данных используется операция <<, из-за неё поток отдаёт все символы, идущие до первого пробела, а сами пробелы игнорируется. Поэтому получается, что в поток вы отдали всю строку, а забираете из потока отдельные слова.
Для того, чтобы работать над словами строки, можно использовать способ, применяемый в языке С: использовать функцию strtok. В таком случае нам можно будет указывать символы-разделители, которыми определяется, что символ делит слово. В самом обычном виде слова делятся знаками препинания: пробел, точка, запятая, восклицательный знак и др. Есть и неудобства, но на некоторые осложняющие случаи чаще все закрывают глаза: например, дефис и тире требует дополнительной обработки, хотя в типографии дефис и тире разные символы, мы часто используем символ дефиса в качестве тире. Я не буду усложнять показываемый код дополнительными обработками, чтобы новички могли понять основное, да и всех случаев возможных проблем я просто не могу предвидеть. Будем считать, что для анализа нам подаются простые строки.
  • Функция strtok это стандартная функция языка С, она позволяет разбивать строки на части
  • Чтобы разбить строку на части функцией strtok, нужно функции подсказать набор символов-разделителей, по которым видно, что идёт несколько слов, а не одно.
  • Для того, чтобы иметь возможность работы с функцие strtok, нужно заинклюдить заголовочный файл string.h

Функция strtok берёт строку и ищет в ней вхождение любого указанного символа-разделителя, при нахождении такого символа этот символ подменяется символом-признаком конца строки. Указательная переменная, которая указывает на символьный массив, может выполнять роль строки, любая строка заканчивается нуль-символом, поэтому при выводе на экран символьных массивов мы наблюдаем не массивы целиком, а только их значимую часть, т. е. строку как она есть. Если в любое место строки вписать нуль-символ, то строка как будто бы обрежется:

Это strtok и делает.
Почему в strtok отдаётся именно ноль для дальнейшего анализа, мне объяснить вам сложно. Скорее всего написавшие функцию программисты немного прогадали с интуитивно-понятным вариантом, решили, что если не другая строка, то пусть будет нулевой указатель. Я усложнять ничего не хочу, поэтому на первое время предлагаю запомнить, что в случае работы с strtok, если нужно продолжать работу с той же строкой, то нужно отдавать нулевой указатель и разделители, а при первом обращении нужно обязательно отдать анализируемую строку и разделители.
Чтобы слова поочерёдно выбирались, мы делаем цикл:

  • Функция strtok разрушает анализируемую строку.
Я уже писал, что функция strtok принудительно пишет символ-признак окончания строки в строку, из-за этого оригинальная строка бьётся.

По этой причине вам нужно подумать перед использованием функции strtok, надо ли вам сохранить оригинальное значение строки или не надо. Сохранить строку в дополнительную переменную несложно, важнее, чтобы вы понимали сам факт разрушения оригинальной строки при показанном подходе.

Когда вы будете смотреть в другие источники, то будете встречать такие термины: лексема и токен. Мне эти термины выносили мозг. Если углубляться в лингвистику, то слово лексема не очень уместно для русского человека из-за наличия падежей в русском языке, а токены — это просто выбираемые по какому-то признаку кусочки текста, в случае со словами токенами оказываются просто слова. Если бы массив состоял из цифр, а делителем была бы цифра 5, то токеном было бы любое число, отделённое символом 5:
3 4 4 3 5 6 2 3 5 3 5 2 1 1 2 5
Токены: 3443, 623, 3, 2112 — ведь словами их трудно назвать.

27 комментариев на «“C++ для начинающих. Строки. Разбить строку на слова”»

  1. Sergio:

    А как разбить строку на слова и записать каждое полученное слово в отдельную переменную?
    Покажите, пожалуйста, хотя бы на примере 2х слов.

    • я могу показать простой пример, если известно сколько в предложении слов. Т.е. известно сколько переменных нужно объявить в программе.
      И этот подход в любом случае идеологически неправильный.

      подойдет такой пример?
      =====================
      немного подрихтуете. пример основан на примере из темы, но в другой среде разработки.

      Если вы под отдельными переменными имели ввиду элементы массива, то извиняйте. Как был задан вопрос, так я и ответил.

    • Если в предложение неизвестное количество слов и оно может быть разным, то для того, чтобы описывать каждое слово в отдельной переменной, нужно каждую переменную создавать во время выполнения программы. Это работа с указателями и выделением памяти. Но все равно все сводится к тому, что после работы программы надо будет очищать выделенную память своими руками, а чтобы ее очищать, нужно где-то хранить адреса. Объяснять долго. Всё сведется к тому что нужен массив, в котором будут храниться занятые системой адреса для их освобождения после завершения работы программы. Это геморрно, неудобно и неэффективно. Или же надо лезти в деревья (стеки, деревья, очереди 🙂 )

  2. здравствуйте. я быстро не могу помочь никак, да и непонятно зачем пропускали если хотите изучить С++
    ваш пример — перегрузка операторов. Перегрузка операторов почти ничего не объясняет в икнапсуляции.

  3. Инкапсуляция

    Инкапсуляция
    Как понимать классы в С++ http://ci-plus-plus-snachala.ru/?p=35
    Немного о private http://ci-plus-plus-snachala.ru/?p=44
    Еще немного о private http://ci-plus-plus-snachala.ru/?p=44
    Инкапсуляция — это то, что к private относится (я бы назвал ее приватизацией, т.к. под слово хорошо подходит и произношением и смыслом, но злые технари не любят когда вещи называют не теми именами, которые им даны)

  4. Nazar:

    Здравствуйте! Не могли бы вы мне помочь? Как разбить файл(.txt) на части по указанным строкам и записать эти части на отдельные файлы. Помогите пожалуйста…..

  5. Guardian:

    Извините, а причём тут С++? Ваш пример — дикая смесь двух языков. Из всего С++ здесь только std::cout всё остальное — С. Почему не используются строковые потоки, кода было бы раз в 5 меньше.

    Уважаемые новички! Помните, что если вы компилите .cpp, это ещё не значит, что вы пишете на С++. Если вы не знаете стандартной библиотеки, вы не знаете С++. Если вы не используете виртуальные функции, вы даже не приступили к ООП. Вы используете мощнейший язык на полпроцента.

    • На занятиях часто ограничивают задания делать без STL и что, это значит учат уже не С++?
      Не зная STL не знаешь С++ — дикая чушь. STL не есть С++, С++ способно жить и без STL
      C++ — это не ООП язык, а мультипарадигменный язык, он поддерживает ООП и только.
      Ну и что, что пример смешан? C++ задумывался как язык, который включает в себя Си.

  6. Hazatdum:

    Здравствуйте, очень интересная статья!
    А можно ли как-нибудь записать еще и сами разделители отдельно? Например есть строка «А=В+С» и вывод был бы
    А
    =
    В
    +
    С

    Помогите, пожалуйста!

  7. Игорь:

    у меня vs2013 studio exspress и он ругается на strtok вот так — erorr C4996: ‘strtok’ подскажите что делать?

    • В настройках проекта добавь _CRT_SECURE_NO_WARNINGS
      Как это сделать, можно посмотреть, например: https://www.youtube.com/watch?v=NZW7djD3mH8
      Как заходить в настройки — дело привычки. Можно как в видео, можно с помощью основного меню:
      Project -> Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions» добавить туда _CRT_SECURE_NO_WARNINGS
      Как именно добавлять, хорошо видно в видео.

  8. Ксюша:

    Здравствуйте, подскажите, как выделить из текста предложения и записать их в отдельные переменные массива? Текст берется из файла. Пусть, например, в тексте всего несколько предложений, 3 или 4.

    • Считывать текст посимвольно. Составлять из считываемого строку до тех пор, пока не обнаружится признак конца предложения. Признак обнаруживается — предложение фиксируется в массиве, строка очищается, индекс обновляется. Нужно использовать вектор или другой динамический массив. С обычным массивом нормально не записать, поскольку заранее неизвестно, сколько предложений будет записано.

  9. Димон:

    Здравствуйте. ПОмогите пожалуйста. Мне нужно выделить слова из строки и проверить их на содержание определенных букв, но как мне выделить слова и поработать над ними?

    • Способ 1: При разбивании строки на слова в момент фиксации слова сразу работать со словом.
      Способ 2: Запоминать слова в вектор, работать с вектором.

      Пример для 1:

      • Димон:

        Спасибо вам огромное. Я тут что-то сам наделал. В итоге я запускаю и почему-то вожу не одну строку, а три, и после ничего не выводиться. Чувствую что-то не так с WORD. Мне нужна длина слова, но я WORD задал как переменная типа char, а чтобы подсчитать длину, нужен тип string, не могу понять. Не подскажите в чем ошибка. Заранее огроменное спасибо.

        • длину у char[] можно вычислить используя готовую функцию:

      • Так уж выходит, что движок сайта ломает Вашу попытку показать мне код. Преобразовать его в исходную форму мне не под силу.

        Или разместите код заново, и при этом попробуйте правильно. (код вставляется в исходном виде между тегами [cpp]КОД[/cpp], или попробуйте использовать онлайн компиляторы, в которых компилировать код, после чего брать ссылку и делится ей.

        https://rextester.com/l/cpp_online_compiler_clang

        Пример сохранённого кода: https://rextester.com/HEFT80097 (сначала написать код, потом run (выполнить) и save (запомнить), будет создана ссылка, которой можно делиться.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Поиск

 
     

Случайная книга в электронном формате

https://www.litres.ru/uriy-magda/programmirovanie-i-otladka-c-c-prilozheniy-dlya-mikrokontrollerov-arm/?lfrom=15589587
Яндекс.Метрика