Подтвердить что ты не робот

Как обычно применяются текстовые редакторы?

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Чарльз Кроули написал гораздо более полное обсуждение " Редактирование текста ", который охватывает значительно более широкие слои буферов (и других возможностей).

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

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

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

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