Запустите и протестируйте приложение. При этом обнаружатся недостатки, на устранение которых понадобится какое-то время, так как более тонкие моменты обработки текстовой информации требуют ясного понимания особенностей выбранной структуры данных и более изощренного программирования. Вы, конечно, заметили, что два одинаковых с семантической точки зрения имени (например, «Joe Doe» и «Joe<пробелы>Doe») считаются разными в нашем алгоритме. Испортят представление об интеллектуальности алгоритма не только лишние пробелы внутри имени, но и пробелы, введенные пользователем до и после имени. Попробуем устранить недостатки.
Введите в класс Form1 новый метод, который будет убирать лишние пробелы, обнаруженные в строке, переданной параметром, и возвращать новую, каноническую строку. Лишними будем считать пробелы, которые встречаются до первого слова имени, после последнего слова и пробелы между словами, если их количество больше одного.
Перед тем, как начать писать код, следует иметь в виду, что строки в C# являются неизменяемыми (immutable). Это означает, что компилятор не позволяет работать со строкой, как с массивом символов в режиме записи, однако в режиме чтения (readonly) такое возможно. Обойти это препятствие позволит специальный класс StringBuilder, определеный в пространстве имен System.Text. Он поддерживает изменяемые (mutable) строки текста и мы используем его для того, чтобы посимвольно копировать элементы старой строки в новую. Алгоритм может быть таким. В цикле пробега по всем символам исходной строки мы либо копируем символы в новую строку sNew, либо игнорируем их. Размер новой строки может быть либо равен, либо меньше размера старой. Перед тем, как возвратить результат, надо привести объект класса StringBuilder к типу string.
private string Trim (string sOld)
{
StringBuilder sNew = new StringBuilder (); // Создаем новую пустую строку
//==== Предполагаем, что сначала идут пробелы
//==== Ваш код
return sNew.ToString(); // Результат вновь приведем к типу string
}
После создания функции Trim вставьте ее вызовы внутрь метода Add. Место вставки определите самостоятельно.
tName.Text = Trim (tName.Text);
tProf.Text = Trim (tProf.Text);
tPhone.Text = Trim (tPhone.Text);
tAddr.Text = Trim (tAddr.Text);
Если вы запустите приложение вновь, то сможете убедиться, что имена, отличающиеся лишь количеством пробелов, считаются эквивалентными, благодаря автоматическому приведению к каноническому виду. Однако, в алгоритме вставки осталась серьезная погрешность, которую вы, возможно, видите и невооруженным глазом. Если так, то исправьте ее, если нет, то попытайтесь обнаружить ошибку экспериментально, затем понять ее суть и исправить. Создайте обработчик нажатия кнопки Удалить.
private void bDel_Click(object sender, System.EventArgs e) { Delete(); }
Введите вспомогательную функцию Delete, которая понадобится еще раз (отклик на клавишу Delete).
private void Delete()
{
int id = list.SelectedIndex; // Находим в списке выделенный элемент
if (id == ListBox.NoMatches) // Если такого нет, уходим
return;
sUndo = list.Items[id].ToString(); // Запоминаем удаленный элемент
list.Items.RemoveAt(id);// Удаляем его из списка
bUndo.Enabled = true; // Кнопка "Отмена" становится доступной
int size = list.Items.Count;
// Скорректируйте переменные sTotal, bModified . . .
if (size == 0)
{ // Если список опустошен, очистите поля ввода
return;
}
// Скорректируйте индекс текушего элемента if (id и т.д.
}
Возвращаясь к ошибке в алгоритме вставки в список новых элементов, приведем набор входных данных, на которых она обнаруживается. Это последовательность имен: "Victor" и "Vic". Попытайтесь вставить одного, а затем другого. Если вы не нашли ошибку, то сделайте это сейчас и исправьте ее. Создайте обработчик нажатия кнопки Найти.
private void bFind_Click(object sender, System.EventArgs e)
{
tName.Text = Trim(tName.Text); // Нормализуем имя человека
int id = list.FindString (tName.Text); // Ищем элемент по имени
if (id == ListBox.NoMatches) // Если не находим, высвечиваем текст
sNotFound.Show();
else
list.SelectedIndex = id; // Иначе, выделяем найденный элемент
}
Для того, чтобы ввести в класс Form1 реакцию на выбор какой-либо строки в окне списка:
1. В режиме Design поставьте фокус в окно списка (list) и в окне Properties нажмите кнопку Events.
2. Найдите в списке событий строку с именем SelectedIndexChanged и дважды щелкните над ней.
В классе формы появится функция реакции на уведомление от ListBox. Вставьте в нее код.
private void list_SelectedIndexChanged (object sender, EventArgs e)
{
sNotFound.Hide(); // Убираем сообщение
int id = list.SelectedIndex; // Определяем индекс выделенной строки
if (id != ListBox.NoMatches) // Защита от побочных эффектов
{
string s = list.Items[id].ToString(); // Выуживаем текстовую строку
//== Разбиваем ее на 6 подстрок При этом используется массив разделителей
string[] ss = s.Split (new Char[] {';', ':'}, 6);
tName.Text = Trim (ss[0]); // Выбираем только нужные подстроки
tProf.Text = Trim (ss[1]);
tPhone.Text = Trim (ss[3]);
tAddr.Text = Trim (ss[5]);
}
}
Здесь использован неподражаемый метод Split, который присутствует в классе String. Он возвращает массив строк текста, а точнее, массив новых объектов типа string. Список разделителей, поданный вторым аргументом, позволяет выделить все необходимые нам лексемы из строки, хранящейся в ListBox’е.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.