Как обычно применяются текстовые редакторы? - PullRequest
48 голосов
/ 28 октября 2010

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

Я просто думаю, если бы я гипотетически интересовался разработкой собственного элемента управления графическим интерфейсом, виджетом или как вы хотите его называть (а я нет), как бы я вообще это сделал?

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

Предположительно, вместо этого используется некоторая изменяемая структура данных, содержащая текст; но выяснение того, как эта структура может выглядеть, кажется мне немного сложной задачей. Произвольный доступ был бы хорош (в любом случае я бы подумал - в конце концов, разве вы не хотите, чтобы пользователь мог прыгать где-нибудь в тексте?), Но потом меня интересует стоимость Скажем, перейдя куда-то посередине огромного документа и сразу начав печатать. Опять же, новичок (скажем, вы сохраняете текст в виде массива символов с изменяемым размером) может привести к очень низкой производительности, я думаю, так как с каждым символом, набранным пользователем, будет огромный объем данных для «смещения» более.

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

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

В любом случае, мне просто интересно узнать, есть ли у кого-нибудь знания по этой теме. Как я уже сказал, я определенно не собираюсь писать свой собственный текстовый редактор; Мне просто любопытно.

Ответы [ 4 ]

36 голосов
/ 28 октября 2010

Одна из распространенных методик (особенно в старых редакторах) называется разделенным буфером. По сути, вы «разбиваете» текст на все перед курсором и все после курсора. Все до этого идет в начале буфера. Все после идет в конце буфера.

Когда пользователь вводит текст, он переходит в пустое пространство между ними без перемещения каких-либо данных. Когда пользователь перемещает курсор, вы перемещаете соответствующее количество текста с одной стороны «разрыва» на другую. Как правило, вокруг одной области много перемещений, поэтому вы обычно перемещаете только небольшие объемы текста за раз. Самое большое исключение - если у вас есть возможность «перейти к строке ххх».

Чарльз Кроули написал гораздо более полное обсуждение темы . Возможно, вы также захотите взглянуть на Craft of Text Editing , который охватывает разделенные буферы (и другие возможности) гораздо глубже.

2 голосов
/ 01 ноября 2010

Некоторое время назад я написал свой собственный текстовый редактор на Tcl (на самом деле, я украл код откуда-то и расширил его до неузнаваемости, ах чудес с открытым исходным кодом).

Как вы упомянули, делать строкиОперации с очень, очень большими строками могут быть дорогими.Таким образом, редактор разбивает текст на более мелкие строки в каждой новой строке ("\ n" или "\ r" или "\ r \ n").Поэтому все, что мне осталось, это редактировать небольшие строки на уровне строк и выполнять операции со списками при перемещении между строками.

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

Также помогает то, что сценарий использования моего текстового редактора используется в качестве редактора для программистов.Например, я реализовал подсветку синтаксиса, но не перенос слов / строк.Так что в моем случае есть карта 1: 1 между новыми строками в тексте и линиями, нарисованными на экране.

Если вы хотите посмотреть, вот исходный код моего редактора: http://wiki.tcl.tk/16056

Это не игрушка Кстати.Я использую его ежедневно в качестве стандартного консольного текстового редактора, если файл не слишком велик для размещения в ОЗУ (Серьезно, что такое текстовый файл? Даже романы, которые обычно имеют размер от 4 до 5 МБ, помещаются в ОЗУ. Я видел только файлы журналовувеличиться до сотен мегабайт).

1 голос
/ 28 октября 2010

Самый простой способ - использовать некоторый класс строкового буфера, предоставляемый языком.Даже простой массив объектов char будет в крайнем случае.

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

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

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

Конечно, этот простой подход быстро приведет к чрезвычайно фрагментированному буферуи я бы подумал о том, чтобы иметь какое-то правило для объединения буферов, когда это уместно, или для отсрочки разделения буфера в случае, например, вставки одного символа.Возможно, будет правило, что у меня будет только 2 внутренних буфера, и я объединю их перед созданием нового - или когда что-то попросит у меня просмотреть весь буфер сразу.Не уверен.

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

Однако,Я определенно не начал бы с неизменяемых объектов String!

1 голос
/ 28 октября 2010

В зависимости от объема текста, который должен быть в редакторе за раз, одна строка для всего буферного подхода, вероятно, подойдет.Я думаю, что Блокнот делает это - когда-нибудь замечал, насколько медленнее становится вставка текста в большой файл?

Наличие одной строки на строку в хэш-таблице кажется хорошим компромиссом.Это сделало бы навигацию к определенной строке и эффективное удаление / вставку без особой сложности.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...