Как сделать срез строки в c

Добавил пользователь Cypher
Обновлено: 04.10.2024

Неформатированные ввод из стандартного потока и вывод в стандартный поток

С помощью функции printf() можно легко вывести на экран строку, содержащую пробелы:

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

На помощь может прийти функция getchar() , осуществляющая посимвольный ввод данных:

В заголовке цикла getchar() возвращает символ, далее записываемый в очередную ячейку массива. После этого элемент массива сравнивается с символом '\n'. Если они равны, то цикл завершается. После цикла символ '\n' в массиве "затирается" символом '\0'. В условии цикла должна быть также предусмотрена проверка на выход за пределы массива; чтобы не усложнять пример, опущена.

Однако в языке программирования C работать со строками можно проще. С помощью функций стандартной библиотеки gets() и puts() получают строку из стандартного потока и выводят в стандартный поток. Буква s в конце слов gets и puts является сокращением от слова string (строка).

В качестве параметров обе функции принимают указатель на массив символов (либо имя массива, либо указатель).

Функция gets() помещает полученные с ввода символы в указанный в качестве аргумента массив. При этом символ перехода на новую строку, который завершает ее работу, игнорируется.
Функция puts() выводит строку на экран и при этом сама добавляет символ перехода на новую строку. Простейший пример использования этих функций выглядит так:

Итак, если вы работаете со строками, а не другими типами данных, при этом нет необходимости выполнять их посимвольную обработку, то удобнее пользоваться функциями puts() и gets() . (Однако функция gets() считается опасной и была выпилена из версии языка C11.)

Массив символов и указатель на строку

Как мы знаем, строка представляет собой массив символов, последний элемент которого является нулевым символом по таблице ASCII, обозначаемым '\0'. При работе со строками также как с численными массивами можно использовать указатели. Мы можем объявить в программе массив символов, записать туда строку, потом присвоить указателю адрес на первый или любой другой элемент этого массива и работать со строкой через указатель:

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

Иногда в программах можно видеть такое объявление и определение переменной-указателя:

Строку, которая была присвоена не массиву, а указателю, также можно получить, обратившись по указателю:

Но давайте посмотрим, что же все-таки происходит, и чем такая строка, присвоенная указателю, отличается от строки, присвоенной массиву.

Когда в программе определяются данные и объявляются переменные, то под них отводится память. При этом данные, которые не были присвоены переменным, поменять в процессе выполнения программы уже нельзя.

Что происходит в примере? В программе вводится строковый объект, который по сути является строковой константой (литералом). Ссылка на первый элемент этой строки присваивается указателю. Мы можем менять значение указателя сколько угодно, переходить к любому из элементов константного массива символов или даже начать ссылаться на совершенно другую строку. Но вот поменять значение элементов строки не можем. Это можно доказать таким кодом:

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

Тем более нельзя делать так:

В данном случае память не была выделена под массив символов, который мы пытаемся считать функцией scanf() ; память была выделена только под указатель. Поэтому записать строку просто некуда. Другое дело, если память была выделена с помощью объявления массива, после чего указателю был присвоен адрес на этот массив:

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

Передача строки в функцию

Передача строки в функцию ничем не отличается от передачи туда массива чисел:

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

Объявите в программе три массива символов. Данные для двух из них получите с помощью вызовов функции gets() . Третий массив должен содержать результат конкатенации (соединения) двух введенных строк. Напишите функцию, которая выполняет конкатенацию строк.

Массив строк и массив указателей

Рассмотрим более сложный пример. Допустим, у нас есть набор строк. Требуется выполнить сортировку строк по возрастанию по признаку длины: сначала вывести самые короткие строки, затем более длинные.

Набор строк можно представить как двумерный массив, т.е. массив, состоящий из одномерных массивов, где каждый одномерный массив — это строка символов:

Представьте себе, что значит выполнить сортировку строк. Это значит, надо поменять местами содержимое множества ячеек памяти. Это достаточно трудоемкая для компьютера работа, особенно если строк очень много. Однако можно поступить по-иному. Достаточно создать массив указателей, каждый элемент которого будет указывать на соответствующую ему строку первого массива. Далее выполнить сортировку указателей, что несомненно быстрее. Конечно, сам массив строк отсортирован не будет, однако благодаря указателям у нас будет хранится отсортированный "срез" массива:

Примечания к программе:

  • На самом деле параметром функции sortlen() является указатель на указатель. Хотя для понимания проще сказать, что параметром является массив указателей на символы. Мы передаем в функцию указатель на первый элемент массива strP, который сам является указателем. Если бы в функции мы инкрементировали переменную s, то переходили бы к следующему элементу-указателю массива strP.
  • Сортировка выполняется методом пузырька: если длина строки, на которую ссылается следующий указатель массива strP, меньше длины строки под текущим указателем, то значения указателей меняются.
  • Выражение strP[i] = &strings[i][0] означает, что элементу массива указателей присваивается ссылка на первый символ каждой строки.

Напишите программу, которая сортирует строки по алфавиту. Для упрощения задачи пусть сортировка выполняется только по первым буквам строк (если первые буквы слов одинаковы, то вторые и последующие символы проверять не надо).

Исходный код примеров из этой статьи можете скачать из нашего github-репозитория.

Допустимо объявление строковых переменных через ключевое слово var :

Для объединения строк используется оператор +:

При работе со String следует помнить, что при переопределении значения переменной создается новый экземпляр строковой переменной в памяти. Поэтому, если вам нужно собрать строку из большого количества составляющих, то использование оператора + не самый лучший вариант. В этом случае будет происходить перерасход памяти: при выполнении операции объединения с присваиванием для очень большого количества подстрок, приложение может аварийно завершиться из-за того, что сборщик мусора не будет успевать удалять неиспользуемые объекты, а новые будут продолжать появляться с большой скоростью. Для решения этой задачи используйте StringBuilder , о нем будет рассказано в конце этого урока.

Создание и инициализация объекта класса String

Для дословного представления строки, для того чтобы проигнорировать управляющие последовательности, используйте префикс @ перед значением. Сравните вывод следующей конструкции:

Если требуется подготовить строковое значение с использованием набора переменных, то можно воспользоваться статическим методом Format класса String , либо префиксом $ :

Можно явно вызвать конструктор типа c передачей в него параметров. Самый простой вариант – это передать строку:

В качестве параметра может выступать массив Char элементов:

Ещё вариант – это указать элемент типа char и количество раз, которое его нужно повторить:

Для создания строки также можно использовать указатели на Char* и SByte* , но в данном уроке эта тема рассматриваться не будет.

Базовый API для работы со строками

В рамках данного раздела рассмотрим наиболее интересные и полезные методы и свойства класса String .

Объединение строк. Оператор +, методы Concat и Join

Сцеплять строки между собой можно с помощью оператора + , при этом, в результате объединения, будет создан новый объект:

В составе API , который предоставляет System . String , есть метод Concat , который может выполнять ту же работу:

Метод Concat позволяет объединить до четырех строк через прямое перечисление. Если нужно таким образом объединить больше строковых переменных и значений, то используйте оператор +. Полезным свойством Concat является то, что он может принять на вход массив элементов типа String и объединить их:

Для объединения элементов с указанием разделителя используется метод Join . В предыдущем примере, элементы в массиве sArr1 уже содержали пробел, это не всегда удобно, решим задачу объединения элементов, которые не содержат разделителей, с помощью Join :

В качестве разделителя можно использовать любую строку:

Поиск и извлечение элементов из строки. Оператор [], методы IndexOf, IndexOfAny, LastIndexOf, LastIndexOfAny, Substring

Для получения символа из строки с конкретной позиции можно использовать синтаксис подобный тому, что применяется при работе с массивами – через квадратные скобки []:

Для решения обратной задачи: поиск индекса первого (последнего) вхождения элемента или сроки в данной строке используются методы IndexOf , IndexOfAny и LastIndexOf , LastIndexOfAny .

В таблице ниже перечислены некоторые из предоставляемых System . String вариантов этих методов.

IndexOf(Char)

Возвращает индекс первого вхождения символа.

IndexOf(Char, Int32)

Возвращает индекс первого вхождения символа начиная с заданной позиции.

IndexOf(Char, Int32, Int32)

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

IndexOf(String)
IndexOf(String, Int32)
IndexOf(String, Int32, Int32)

Назначение методов совпадает с перечисленными выше, но поиск выполняется для строки.

IndexOfAny(Char[])
IndexOfAny(Char[], Int32)
IndexOfAny(Char[], Int32, Int32)

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

Last IndexOf([Char | String])
Last IndexOf ( [Char | String], Int32)
Last IndexOf ( [Char | String], Int32, Int32)

Возвращает индекс последнего вхождения символа или строки. Можно задавать индекс, с которого начинать поиск и количество проверяемых позиций. [Char | String] – означает Char или String

LastIndexOfAny(Char[])
LastIndexOfAny(Char[], Int32)
LastIndexOfAny(Char[], Int32, Int32)

Возвращает индекс последнего вхождения любого из переданных в массиве элементов.Можно задавать индекс с которого начинать поиск и количество проверяемых позиций

Для определения того, содержит ли данная строка указанную подстроку, а также для проверки равенства начала или конца строки заданному значению используйте методы: Contains , StartsWith и EndsWith .

Contains(Char)
Contains(String)

Возвращает True если строка содержит указанный символ или подстроки.

StartsWith(Char)
StartsWith(String)

Возвращает True если строка начинается с заданного символа или подстроки.

EndsWith(Char)
EndsWith(String)

Возвращает True если строка заканчивается на заданный символ или подстроку.

Задачу извлечения подстроки из данной строки решает метод SubString :

Substring(Int32)

Возвращает подстроку начиная с указанной позиции и до конца исходной строки.

Substring(Int32, Int32)

Возвращает подстроку начиная с указанной позиции с заданной длины.

Сравнение срок

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

Для сравнения также можно использовать метод Equals , но это менее удобный вариант:

Модификация срок

Класс String предоставляет довольно большое количество инструментов для изменения строк.

Вставка строки в исходную в заданную позицию осуществляется с помощью метода Insert :

Для приведения строки к заданной длине с выравниванием по левому (правому) краю с заполнением недостающих символов пробелами используются методы PadLeft и PadRight :

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

Remove(Int32)

Удаляет все символы начиная с заданного и до конца строки.

Remove(Int32, Int32)

Удаляет с указанной позиции заданное число символов.

Замена элементов строки производится с помощью метода Replace . Наиболее часто используемые варианты – это замена символа на символ и строки на подстроку:

Для преобразования строки к верхнему регистру используйте метод ToUpper() , к нижнему – ToLower() :

За удаление начальных и конечных символов отвечают методы, начинающиеся на Trim (см. таблицу ниже).

Удаляет символы пробелы из начала и конца строки.

Удаляет экземпляры символа из начала и конца строки.

Удаляет экземпляры символов из начала и конца строки.

TrimStart()
TrimStart(Char)
TrimStart(Char[])

Удаляет экземпляры символов из начала строки.

TrimEnd()
TrimEnd(Char)
TrimEnd(Char[])

Удаляет экземпляры символов из конца строки.

Методы и свойства общего назначения

Рассмотрим некоторые из полезных методов и свойств, которые не вошли в приведенные выше группы.

System.Length – возвращает длину строки:

System.Split() – разделяет заданную строку на подстроки, в качестве разделителя используется указанный через параметр символ (или группа символов):

System.Empty – возвращает пустую строку.

Форматирование строк

Под форматированием строк, в рамках данного раздела, понимается встраивание в строку различных элементом (число, дата и т.п.), представленных в заданном формате. Форматирование можно осуществлять с помощью метода ToString с передачей в него нужных описателей, метода Format , который, в качестве аргументов, получает строку со специальными вставками, определяющими представление элементов и непосредственно сами элементы.

Для начала рассмотрим на нескольких примерах работу с этими методоми:

Каждый элемент форматирования представляется следующим образом:

где index – это индекс элемента, которым будет замещена данная конструкция;

alignment – выравнивание;

formatString – формат.

Ниже приведены примеры использования элементов форматирования:

Представление чисел

Для представления чисел используются следующие описатели формата (список не полный, более детальную информацию можете найти в официальной документации):

Описатель формата

“C” или “c”

“D” или “d”

Представление целого числа.

“E” или “e”

Представление числа в экспоненциальном виде.

“F” или “f”

Представление числа в формате с плавающей точкой.

“P” или “p”

Представление процентов, выводит число умноженное на 100 со знаком процента.

Сегодня мы поговорим об операциях взятия индекса и среза. Номера символов в строке (а также в других структурах данных: списках, кортежах) называются индексом.

Каждому символу в строке соответствует индексный номер, начиная с 0. При попытке доступа к несуществующему индексу возникает исключение IndexError. Например:

В Python также поддерживаются отрицательные индексы, при этом нумерация идёт с конца, например:

Прямой доступ к строке

При использовании прямого доступа к строке, тогда нумерация начинается с нуля. Пример:

В качестве примера прямого доступа к элементам строки напишем программу доступа к случайному символу строки. Листинг:

На первый взгляд кажется, что мы изменили строку, но на самом деле Python создал строку “Пока” и присвоил это значение переменной message.

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

В данном примере мы создали строку message. Мы можем обратиться к message[1] и прочитать это значение. Но нельзя присвоить message[1] новое значение. Интерпретатор сообщает что тип str не поддерживает поэлементное назначение.

Срезы

Срез (slice) — это извлечение из данной строки одного символа или некоторого фрагмента подстроки или подпоследовательности. Есть три формы срезов.

Самая простая форма среза: взятие одного символа строки, а именно, S[i] — это срез, состоящий из одного символа, который имеет номер i, при этом считая, что нумерация начинается с числа 0.

Исходя из вышесказанного если S=’Hello’, то S[0]==’H’, S[1]==’e’, S[2]==’l’, S[3]==’l’, S[4]==’o’.

Срез с двумя параметрами: S[a:b] возвращает подстроку из b-a символов, начиная с символа c индексом a, то есть до символа с индексом b, не включая его. Например, S[1:4]==’ell’, то же самое получится если написать S[-4:-1].

Можно использовать как положительные, так и отрицательные индексы в одном срезе, например, S[1:-1] — это строка без первого и последнего символа. При использовании такой формы среза ошибки IndexError никогда не возникает.

Если задать срез с тремя параметрами S[a:b:d], то третий параметр задает шаг, то есть будут взяты символы с индексами a, a+d, a+2*d и т.д.

При задании значения третьего параметра, равному 2, в срез попадет кажый второй символ, а если взять значение среза, равное -1, то символы будут идти в обратном порядке.

Также с помощью срезов можно не только извлекать элементы, но и добавлять и удалять элементы:

Демо-программа “Срезы”

Создадим небольшую программу для демонстрации “Срезов”. Листинг:

Первым делом мы присваиваем начальной позиции значение None. Данное ключевое слово в Python представляет пустое значение. Означает только одно – значение еще не присвоено.

В цикле пользователь вводит начальную и конечную позицию. Как и при индексировании, можно использовать отрицательные номера.

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

то формируется следующая коллекция:


Каждый символ имеет свой индекс, начиная с нулевого. Первый символ в Python всегда имеет нулевой индекс.

Для обращения к тому или иному символу используется следующий синтаксис:

и так далее. Но, если указать неверный индекс, например:

lastIndex = len( ) – 1

То есть, к последнему индексу мы можем обратиться так:

Но это не очень удобно. Поэтому разработчики языка Python решили, что отрицательные индексы будут означать движение по строке с конца в начало. И предыдущую запись можно переписать так:

Видите? Это намного удобнее. То есть, у строк есть еще такие отрицательные индексы:


Также в Python можно использовать доступ к отдельному символу непосредственно у строкового литерала:

Иногда это бывает удобно.

Срезы

Часто в программировании требуется выбрать не один какой-то символ, а сразу несколько. Для этого используются так называемые срезы. Их работу проще показать на конкретных примерах. Пусть у нас есть наша строка:

Поэтому, мы должны записать срез так:

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

получим ту же самую строку, не копию! Это можно проверить так:

Увидим одно и то же значение id для обеих переменных, это означет, что они ссылаются на один и тот же объект.

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

и использовать отрицательный шаг:

в этом случае символы будут перебираться в обратном порядке.

Строка – неизменяемый объект

Далее, при работе со строками следует помнить, что это неизменяемый объект, то есть, мы не можем изменять в строковом объекте уже существующие символы, то есть, вот такая запись:

приведет к ошибке, говорящая о том, что строка не может быть изменена. Тогда как в Python нам изменять строки? Для этого создается новая строка с нужным содержимым. Например, изменим строку

Это можно сделать так:

В результате строка myStr ссылается на новую измененную строку, а msg осталась прежней.

Задания для самоподготовки

3. Напишите программу определения слова палиндрома (это слова, которые одинаково читаются в обоих направлениях, например, анна, abba и т.п.). Слово вводится с клавиатуры.

5. Разделите введенное с клавиатуры предложение на слова (слова разделяются пробелом).

Видео по теме


































































© 2022 Частичное или полное копирование информации с данного сайта для распространения на других ресурсах, в том числе и бумажных, строго запрещено. Все тексты и изображения являются собственностью сайта

Читайте также: