Programming Taskbook


E-mail:

Пароль:

Регистрация пользователя   Восстановление пароля

English

ЮФУ SMBU

Электронный задачник по программированию

©  М. Э. Абрамян (Южный федеральный университет, Университет МГУ-ППИ в Шэньчжэне), 1998–2024

 

Решения | C#, VB.NET, F# | Обработка строк

PrevNext


Выполнение задания на обработку строк: String9

Особенности выполнения заданий на обработку символов и строк рассмотрим на примере задания String9.

String9°. Дано четное число N (> 0) и символы C1 и C2. Вывести строку длины N, которая состоит из чередующихся символов C1 и C2, начиная с C1.

Создание программы-заготовки и знакомство с заданием

Проект-заготовку для решения задания String9 можно создать с помощью модуля PT4Load. В созданный проект будет входить файл с именем String9; его расширение зависит от выбранного языка: .cs для C#, .vb для VB.NET и .fs для F#. Приведем текст этого файла без начальных директив:

[C#]

public static void Solve()
{
    Task("String9");

}

[VB.NET]

Sub Solve()
    Task("String9")

End Sub

[F#]

let Solve = pt.Task "String9"

После запуска программы на экране появится окно задачника. На рисунке приведены два варианта представления окна (в режиме с динамической и с фиксированной компоновкой) в случае использования языка C#:


Данные символьного и строкового типа в окне задачника заключаются в кавычки; это позволяет, в частности, отличить числовые данные (например, 2) от символьных и строковых данных, содержащих цифры (например, строки "2"). Кроме того, кавычки дают возможность увидеть пробелы, находящиеся в начале или в конце строк.

Ввод исходных данных

Добавим в процедуру Solve фрагмент, обеспечивающий ввод исходных данных. При этом будем учитывать, что данные символьного типа надо вводить с помощью функции GetChar, а данные целого типа — с помощью функции GetInt:

[C#]

public static void Solve()
{
    Task("String9");
    char c1 = GetChar(), c2 = GetChar();
    int n = GetInt();
}

[VB.NET]

Sub Solve()
    Task("String9")
    Dim c1 = GetChar(), c2 = GetChar(), n = GetInt()
End Sub

[F#]

let Solve = pt.Task "String9"
let c1 = string(pt.GetChar())
let c2 = string(pt.GetChar())
let n = pt.GetInt()

Мы намеренно ввели данные не в том порядке, в котором они указаны в окне задачника. В решении на языке F# мы сразу преобразовали введенные символы к типу string, так как в дальнейшем они будут использоваться в строковых выражениях.

Запуск нового варианта программы уже не будет считаться ознакомительным, поскольку в программе выполняется ввод исходных данных. Так как порядок ввода исходных данных является ошибочным, этот вариант решения будет признан неверным и приведет к сообщению «Неверно указан тип при вводе исходных данных. Для ввода 1-го элемента (целого типа) использована переменная символьного типа».

Напомним правило, определяющее порядок ввода и вывода данных для задачника Programming Taskbook: ввод и вывод данных производится по строкам (слева направо), а строки просматриваются сверху вниз.

Исправим процедуру Solve, изменив в ней порядок ввода исходных данных:

[C#]

    int n = GetInt();
    char c1 = GetChar(), c2 = GetChar();

[VB.NET]

    Dim n = GetInt(), c1 = GetChar(), c2 = GetChar()

[F#]

let n = pt.GetInt()
let c1 = string(pt.GetChar())
let c2 = string(pt.GetChar())

Теперь исходные данные вводятся правильно. Первый этап решения задачи пройден.

Формирование требуемой строки и ее вывод

Для формирования нужной строки воспользуемся операцией сцепления строк («+» в языке C# и F#, «&» в языке VB.NET), после чего выведем полученную строку методом Put:

[C#]

public static void Solve()
{
    Task("String9");
    int n = GetInt();
    char c1 = GetChar(), c2 = GetChar();
    string s = "";
    for (int i = 0; i < n; i++)
        s = s + c1 + c2;
    Put(s);
}

[VB.NET]

Sub Solve()
    Task("String9")
    Dim n = GetInt(), c1 = GetChar(), c2 = GetChar()
    Dim s = ""
    For i = 1 To n
        s = s & c1 & c2
    Next
    Put(s)
End Sub

[F#]

let Solve = pt.Task "String9"
let n = pt.GetInt()
let c1 = string(pt.GetChar())
let c2 = string(pt.GetChar())
let mutable s = ""
for i in 1 .. n do
    s <- s + c1 + c2
pt.Put(string s)

В варианте для VB.NET обратите внимание на новую для языка Visual Basic возможность описания переменной цикла непосредственно в заголовке цикла.

Операция сцепления в F# работает только для строковых переменных; именно поэтому мы выполняем преобразование введенных символов к типу string. Также заметим, что в языке F# переменные по умолчанию считаются неизменяемыми, поэтому для изменения строковой переменной s необходимо объявить ее с ключевым словом mutable, а при изменении использовать оператор <- вместо =.

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

"a1a1a1a1a1*

Красная звездочка, расположенная в конце строки, отображаемой на экране, означает, что длина полученной строки превышает длину контрольной (т. е. «правильной») строки. Для того чтобы увидеть на экране всю полученную строку, достаточно подвести курсор мыши к строке со звездочкой; при этом полный текст строки появится во всплывающей подсказке.

Примечание. Красная звездочка может появиться и при выводе ошибочных числовых данных. Например, если ожидается целое число в диапазоне от 1 до 99, а получено число 10000, то на экран будет выведена только первая цифра этого числа, за которой будет указана красная звездочка: 1*.

Правильное решение, его тестирование и просмотр результатов

Ошибка в предыдущей программе возникла из-за неверного указания количества итераций цикла. Действительно, на каждой итерации к строке добавляется по два символа, поэтому после n итераций строка будет содержать 2n символов (а не n, как требуется в задании).

Для исправления ошибки достаточно вдвое уменьшить число итераций, изменив заголовок цикла следующим образом (обратите внимание на использование операции целочисленного деления \ в заголовке цикла для языка VB.NET):

[C#]

    for (int i = 0; i < n / 2; i++)

[VB.NET]

    For i = 1 To n \ 2

[F#]

for i in 1 .. n / 2 do

После запуска исправленной программы и успешного прохождения 5 тестов мы получим сообщение «Задание выполнено!». Нажав клавишу [F2], мы можем вывести на экран окно результатов, в котором будут перечислены все наши попытки решения задачи (заглавная буква «S», которая указывается перед датой, означает, что при выполнении задания использовался язык C# — «C Sharp»):

String9   S24/03 11:37 Ознакомительный запуск.
String9   S24/03 11:48 Неверно указан тип при вводе исходных данных.
String9   S24/03 11:49 Запуск с правильным вводом данных.
String9   S24/03 11:49 Ошибочное решение.
String9   S24/03 11:52 Задание выполнено!

В случае выполнения задания на языке VB.NET перед датой указывается буква «B» — «Basic», а в случае языка F# — буква «F» (для обозначения языков платформы .NET в окне результатов используются заглавные буквы).

Примечание 1. С использованием класса StringBuilder задачу можно решить, заполняя требуемую строку посимвольно. Приведем соответствующий вариант решения:

[C#]

public static void Solve()
{
    Task("String9");
    int n = GetInt();
    char c1 = GetChar(), c2 = GetChar();
    StringBuilder s = new StringBuilder(n);
    s.Length = n;
    for (int i = 0; i < n / 2; i++)
    {
        s[2 * i] = c1;
        s[2 * i + 1] = c2;
    }
    Put(s.ToString());
}

[VB.NET]

Sub Solve()
    Task("String9")
    Dim n = GetInt(), c1 = GetChar(), c2 = GetChar()
    Dim s = New StringBuilder(n)
    s.Length = n
    For i = 0 To n \ 2 - 1
        s(2 * i) = c1
        s(2 * i + 1) = c2
    Next
    Put(s.ToString())
End Sub

[F#]

let Solve = pt.Task "String9"
let n = pt.GetInt()
let c1 = pt.GetChar()
let c2 = pt.GetChar()
let s = new StringBuilder(n)
s.Length <- n
for i in 0 .. n / 2 - 1 do
    s.[2 * i] lt;- c1
    s.[2 * i + 1] lt;- c2
pt.Put(string s)

Класс StringBuilder описан в пространстве имен System.Text, которое автоматически подключается к заготовкам программ благодаря директивам using System.Text (язык C#), Imports System.Text (язык VB.NET) и open System.Text (язык F#). В данном варианте решения для языка F# не требуется преобразовывать введенные символьные данные к строковому типу.

Следует также обратить внимание на преобразование объекта s к «обычному» строковому типу string при его выводе (если попытаться вывести результат без такого преобразования, т. е. в виде Put(s), то задачник выведет сообщение об ошибке «В методе Put указан параметр недопустимого типа StringBuilder»).

В конструкторе StringBuilder указывается переменная n; это позволяет задать емкость строки s (т. е. размер массива символов, используемого для хранения данной строки). Однако длина созданной строки s (т. е. количество фактически содержащихся в ней символов) остается равной 0, и для того чтобы положить ее равной нужной длине, требуется изменить свойство s.Length. Необходимость использования класса StringBuilder объясняется тем, что обычные строки (типа string) являются неизменяемыми; в частности, их символы и свойство Length доступны только для чтения.

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

[F#]

let Solve = pt.Task "String9"
let n = pt.GetInt()
let c1 = string(pt.GetChar())
let c2 = string(pt.GetChar())
let rec result k s =
    if k > 0 then
        result (k-1) s + c1 + c2
    else
        s
pt.Put(result (n / 2) "")

PrevNext

 

Рейтинг@Mail.ru

Разработка сайта:
М. Э. Абрамян, В. Н. Брагилевский

Последнее обновление:
01.01.2024